Magnolia JCX
This project is no longer maintained and marked as deprecated since it's no longer actively used.
Magnolia JCX is a module which attempts to support JAXB annotations in order to access Jackrabbit repositories. Here’s an introduction into JCX: JCX
Current GAV:
<dependency>
<groupId>com.kasisoft.mgnl</groupId>
<artifactId>ks-mgnl-jcx</artifactId>
<version>0.5</version>
</dependency>
compile 'com.kasisoft.mgnl:ks-mgnl-jcx:0.5'
libraryDependencies += "com.kasisoft.mgnl" % "ks-mgnl-jcx" % "0.5"
Quick Tip: Checkout the test cases of the project in order to get a good impression of the capabilities.
Default behaviour
The following rules will be followed by the JCX module. If you encounter a discrepancy to these rules it’s likely to be an unintended error, so I would appreciate to get an error report:
- String values are never empty. Therefore they are either null or do contain non whitespace characters.
- String values are always being trimmed (I thought about making this modification configurable but I chose this simple solution as I consider the use of leading/trailing whitespace to be a fringe case).
- Collections are never null, so you’re getting empty Collections.
- Make no assumptions whether the collections are mutable or not. Whenever the unmarshalling process fails it’s generating a JcxException (as a general rule I’m always using module specific exception so the user if a module won’t be forced to deal with plenty of other exception types).
Handling of required properties must be explicitly configured. The default behaviour is that a missing but required value is only logged (subject to change !). You can update the JcxUnmarshaller accordingly but the handler should only be set once within your application:
public class MyModule implements ModuleLifecycle {
private JcxUnmarshaller unmarshaller;
@Inject
public MyModule(JcxUnmarshaller unmarshaller) {
this.unmarshaller = unmarshaller;
}
@Override
public void start(ModuleLifecycleContext moduleLifecycleContext) {
unmarshaller.setUnsatisfiedRequireHandler(this::requireHandler);
}
@Override
public void stop(ModuleLifecycleContext moduleLifecycleContext) {
}
private void requireHandler(Node node, String type, String property) {
throw new RuntimeException("can't access property '" + property + "' of type '" + type + "'");
}
} /* ENDCLASS */
XML attributes
-
The annotation @XmlAttribute must be used for the following datatypes:
- boolean
- byte
- short
- char
- int
- long
- float
- double
- String
- Adapted types
- Node
- The attributes required and name of @XmlAttribute are supported.
- Primitive types imply that required = true no matter what you set.
-
The following special names can be used to extract meta data from a node:
- @depth - Depth of the node
- @uuid, @identifier - Identifier of the node
- @name - Name of the node
- @path - Path of the node
- @nodeType - Name of the primary node type
Examples
// property name: age, required: false
@XmlAttribute
private Integer age;
// property name: gender, required: true
@XmlAttribute
private boolean gender;
// meta property name: @uuid, required: false
@XmlAttribute(name = "@uuid")
private String identifier;
// property name: duration, required: true
@XmlAttribute(required = true)
private Long duration;
// property name: result, required: true
@XmlAttribute(required = true, name = "result")
private Float wumpi;
If you want to use an adapted type you need to provide a corresponding @XmlJavaTypeAdapter . The most likely scenario are the conversions between an Enumeration and a String.
enum Position {
left, center, right;
}
class PositionAdapter extends XmlToTypeAdapter<String, Position> {
public PositionAdapter() {
// see com.kasisoft.libs.common.xml.adapters;
super(new EnumerationAdapter<>(Position.class));
}
}
@XmlAttribute
@XmlJavaTypeAdapter(PositionAdapter.class)
private Position position;
XML elements
The annotation @XmlElement has to be used for complex types when they’re being used alone or as part of a Collection. The attribute values name and required are supported. Each type must be capable to be created using the Guice framework which means that the type either has an empty default constructor or the parameters can be injected with values through Guice.
Examples
// property name: link, required: false
@XmlElement
LinkModel link;
// property name: address, required: true
@XmlElement(required = true)
Address address;
// property name: contacts, required: false
// NOTE: The GenericsType annotation is subject to change
@XmlElement
@GenericsType(Contact.class)
List<Contact> contacts;
// property name: baskets, required: false
// NOTE: An XmlElementWrapper should be used if the list elements are located under a subnode which serves as a container node
@XmlElementWrapper
@XmlElement
@GenericsType(Basket.class)
List<Basket> baskets
Extensions
The following examples provides extensions to the general mechanism:
// the dialog definition stores the UUID to contact workspace in the property 'author'.
// this annotation uses this to use the referred node as a data source for the class ContactModel
@JcxReference(value = "contacts", property = "author")
ContactModel author;
The JcxUnmarshaller supports the following interfaces:
public interface IPostProcessor {
/**
* This function will be executed after properties had been loaded.
*/
void postprocess();
} /* ENDINTERFACE */
public interface IContent {
boolean hasContent();
} /* ENDINTERFACE */
These interfaces don’t need to be implemented. Their meaning is as followed:
IPostProcessor
The function postprocess will be called after the JcxUnmarshaller has performed all configuration operations on an instance. It allows you to handle scenarios where model attributes are interdependent or if you want to provide derived information of model attributes.
IContent
The function hasContent is used to decide whether an instance has a value or not. If you return false the object is interpreted as invalid and thus dismissed. This means that a null value is used instead or in case of a Collection it’s not being added so it’s safe to assume that each element in a list can be considered to be complete.
Technical Documentation
TO BE DONE