Dynamic Content Beans
Introduction
Goal
Use dynamic runtime content bean generation for your document types.
Background
For typical document types created using the Document Type Editor and image sets configured using the Gallery Manager, content bean classes are dynamically generated at runtime. Changes are available immediately, for example in Freemarker templates, without the need for a rebuild & restart cycle in the development environment. This greatly increases development velocity compared to manually developing content beans or generating them using the Beanwriter tool.
Dynamically Generate Content Beans
Dynamic bean generation supports all content types which are document types, compound types, and image set types. All standard fields and compound typed fields available in the Document Type Editor are supported.
The dynamic bean feature generates the content beans at runtime when needed. With the help of code generation (Byte Buddy), a content bean class is generated that contains getters for all the fields described in the node type definition. Byte Buddy is a code generation and manipulation library for creating and modifying Java classes at runtime.
Since the bean classes are only generated once (or after a change of a document type via the document type editor), there is no impact on performance.
Bean generation logic runs for your content types regardless of content bean classes being present for the content types in your project. If there is no existing content bean Java class related to a document type in the result of automatic scannen for content bean annotated classes, the runtime-generated bean will extend from BaseDocument and thus developers can add some general methods to their BaseDocument class if they want.
The bean class is generated on the fly by reading definitions in the related JCR nodes. A sample generated class is for the document type myproject:mydocumentype as follows
... public BaseDocument$Mydocumenttype$8btLfpVF extends BaseDocument { public String getStringTypeField() { return (String) super.getProperty("myproject:stringTypeField"); } public Calendar getDateTypeField() { return (Calendar) super.getProperty("myproject:dateTypeField"); } public HippoHtml getRichTextEditorCompoundType() { return super.getHippoHtml("myproject:richTextEditorCompoundType"); } public HippoGalleryImageSet getImagelinkCompoundType() { return (HippoGalleryImageSet) super.getLinkedBean("myproject:imagelinkCompoundType",HippoGalleryImageSet.class); } ... ... }
If the project doesn’t have any BaseDocument class, which means that no class has @Node(jcrType="myproject:basedocument") annotation, the generated bean for the document types extends from the HippoDocument class.
The content beans for compound types are generated by extending from the HippoCompound class.
Enhance Existing Content Bean Classes
If an implementation project contains any custom content bean classes, a new class may be generated, extending from the existing content bean class and adding any getter methods that are missing.
The existing bean class:
@Node(jcrType = "myproject:mydocumentype") public class Mydocumenttype extends BaseDocument { }
The dynamically generated bean class:
public Mydocumenttype$Mydocumenttype$8btLfpVF extends Mydocumenttype { public String getMissingfield() { return (String) super.getProperty("myproject:missingfield"); } }
A new content bean class is generated for the existing bean class on the fly if the existing class does not have the annotation @HippoEssentialsGenerated or if present does not have @HippoEssentialsGenerated(allowModifications=false). One exception is that if the existing bean is up-to-date and has getter methods for all of the fields in the content type, a new bean class is not generated and the existing bean is used.
Mark Existing Bean Classes as Not Modifiable
You can exclude your bean classes from any runtime modification by setting the HippoEssentialsGenerated annotation's allowModifications parameter to false.
@HippoEssentialsGenerated(internalName = "myproject:mydocumentype", allowModifications = false) @Node(jcrType = "myproject:mydocumentype") public class Mydocumenttype extends BaseDocument { ... ... }
Support for Custom Bean Class Hierarchies
If the existing bean class of either a document type or a compound type has a parent class of another document type or compound type instead of BaseDocument, then the dynamic bean generates the new classes with the same class hierarchy of the existing HippoBeans.
In the following example, the generated class of the Childdocument type, myproject:childdocument, is extended from the generated class of the Parentdocument type, myproject:parentdocument.
public class BaseDocument$Parentdocument$IB2IXnoT extends BaseDocument { ... ... } public class BaseDocument$Parentdocument$IB2IXnoT$Childdocument$2E9PXydT extends IB2IXnoT { ... ... }
Handling of Custom Image Sets
Custom image sets can be created using the Gallery Manager tool in the Essentials setup application. When the developer defines a custom image set with the choice of updating the current images, then the property with name gallerytype on the /content/gallery node is set to the name of the custom image set.
While generating the beans, the value of the gallerytype property is taken into account and the bean is generated with this image set type.
Disable Dynamic Bean Generation At System Level
Dynamic bean generation is active by default. You can disable dynamic bean generation by setting the system property Dynamic.bean.generation to false. To disable dynamic bean generation, pass a parameter to the JVM as follows:
-Ddynamic.bean.generation=false
Use Dynamic Content Beans with the Content REST API
Dynamic bean generation is compatible with the Content REST API.
Custom REST resources are not supported at the moment. If your project contains custom REST resources, it is recommended that you mark the related content bean classes as not modifiable.