|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: REQUIRED | OPTIONAL | DETAIL: ELEMENT |
@Target(value={METHOD,TYPE}) @Retention(value=RUNTIME) public @interface MOConstructionDescriptor
Defines the methods to construct a bean when reading an XML document. The MOConstructionDescriptor allows to define what contructor to use or factory method to use, and what parameters to pass to the constructor or factory method.
The annotation can appear on a top level bean (annotation with MOPersistentBean
) or on a property which
contains a bean or a collection of beans. If the annotation appears both on the bean and on a property, the
definition on the property takes presedence.
note that there is no setter method for the 'name' property - it is not required anymore because the framework sets the property via the constructor.
@MOPersistentBean(xmlName = "HelloWorld") @MOXmlNamespace(value = "http://example.abra.com/helloWorld", preferedPrefix = "ex1") @MOConstructionDescriptor(constructorArgs = { @MOConstructorArg(sourceProperty = "name", sourcePropertyOf = SourcePropertyOf.constructedInstance)}) public class HelloWorld { private String name; public HelloWorld(String name) { this.name = name; } @MOProperty() public String getName() { return name; } }
customerName
attribute of the owner customer).
when mapping those classes to XML, because the order XML element is written as a child of the customer XML
element, there is no need to write the customerName
again under the order
XML element.
Instead, one creates a constructor for the Order
class which accepts the customerName
as a parameter and maps it to a parent attribute using the annotation
MOConstructorArg(sourceProperty = "customerName", sourcePropertyOf = SourcePropertyOf.parent)
@MOPersistentBean(xmlName = "order") @MOXmlNamespaceRef(NodeTypeWithFactory.class) public class Order { private String customerNameOfOrder; private String orderDescription; private int orderID; public Order(String customerNameOfOrder, int orderID) { this.customerNameOfOrder = customerNameOfOrder; this.orderID = orderID; } order() {} public String getCustomerNameOfOrder() { return customerNameOfOrder; } @MOProperty public String getOrderDescription() { return orderDescription; } public void setOrderDescription(String orderDescription) { this.orderDescription = orderDescription; } @MOProperty public int getOrderID() { return orderID; } } @MOPersistentBean(xmlName = "customer") @MOXmlNamespaceRef(NodeTypeWithFactory.class) public class Customer { private String customerName; private int id; private List<Order> orders = new ArrayList<Order>(); @MOProperty public String getCustomerName() { return customerName; } public void setCustomerName(String customerName) { this.customerName = customerName; } @MOProperty public int getId() { return id; } public void setId(int id) { this.id = id; } @MOProperty @MOConstructionDescriptor(constructorArgs = { @MOConstructorArg(sourceProperty = "customerName", sourcePropertyOf = SourcePropertyOf.parent), @MOConstructorArg(sourceProperty = "orderID", sourcePropertyOf = SourcePropertyOf.constructedInstance) }) public List<Order> getOrders() { return orders; } }
Order
instances.
The factory method again requires two parameters (the customerNameOfOrder
and orderID
parameters).
The factory class can be
And the mapping of the list in thepublic class OrdersFactory { public static Order createOrder(String customerNameOfOrder, int orderID) { Order order = new Order(); order.setCustomerNameOfOrder(customerNameOfOrder); order.setOrderID(orderID); return order; } }
Customer
class changes to
@MOProperty @MOConstructionDescriptor( factoryClass = OrdersFactory.class, factoryMethod = "createOrder", constructorArgs = { @MOConstructorArg(sourceProperty = "customerName", sourcePropertyOf = SourcePropertyOf.parent), @MOConstructorArg(sourceProperty = "orderID", sourcePropertyOf = SourcePropertyOf.constructedInstance) }) public List<Order> getOrders() { return orders; }
MOConstructionDescriptor
is only allowed when used on a property, it is not allowed when used for a bean.
The Parent Bean in this case is the Orders
class and the child bean is the Order
bean.
The @MOConstructionDescriptor defines to use the method createOrder
to create order instances,
where the method is an instance method of the parent bean instance.
public class Orders { @MOProperty @MOConstructionDescriptor( factoryMethod = "createOrder", constructorArgs = { @MOConstructorArg(sourceProperty = "orderID", sourcePropertyOf = SourcePropertyOf.constructedInstance) }) public List<Order> getOrders() { return orders; } public Order createOrder(int orderID) { Order order = new Order(); order.setCustomerNameOfOrder(this.getCustomerNameOfOrder); order.setOrderID(orderID); return order; } }
Order
class. We change the constructor to accept only one parameter,
the orderID
. The parameter customerNameOfOrder
we now want to initialize as a property,
but we do not want to map it to XML at the Order
class (because the Customer
class
already maps this value).
This is done using the MOInitializerProperty
annotation that maps a property from the parent class
(Customer
in the example) to a property of the child class (Order
in the example).
We change the Order
class to be
the mapping of the@MOPersistentBean(xmlName = "order") @MOXmlNamespaceRef(NodeTypeWithFactory.class) public class Order { private String customerNameOfOrder; private String orderDescription; private int orderID; public Order(int orderID) { this.orderID = orderID; } public void setCustomerNameOfOrder(String customerNameOfOrder) { this.customerNameOfOrder = customerNameOfOrder; } public String getCustomerNameOfOrder() { return customerNameOfOrder; } ... }
Customer
class changes to be
@MOProperty @MOConstructionDescriptor( constructorArgs = { @MOConstructorArg(sourceProperty = "orderID", sourcePropertyOf = SourcePropertyOf.constructedInstance)}, InitializerProperties = { @MOInitializerProperty(sourceProperty = "customerName", targetProperty = "customerNameOfOrder")} )
Shape
bean, and two subclasses Circle
and Square
.
We map all three classes, and define another class named Drawing
with a property which is a collection
of Shape
instances or a single property of type Shape
. Substitution groups kick into play
(for more details about mapping substitution groups see
MOXmlGlobalBeanRef
).
If we want to create the instances of the Shape
subclasses using a factory, we face an interesting
question - how does the factory know which subclass to instantiate? the obviuos answer is by the parameters passed
to the factory method. The parameters can be read from the XML document, from the instantiated bean or the parent
bean of the instantiated one (see the previous examples). However, the substitution groups mechanism includes
one additional piece of information - the name of the child bean XML element, which is automatically mapped
to the class of the bean expected to be instantiated.
To define that the factory method will accept this parameter - a parameter of type class which is the class of the instantiated bean, one has to be reminded that all beans in Java have a special read-only property named class. By defining a parameter named class, the factory will recieve the expected class to be instantiated.
The constructor descriptor is then
@MOProperty @MOConstructionDescriptor( factoryClass = ShapesFactory.class, factoryMethod = "createShape", constructorArgs = { @MOConstructorArg(sourceProperty = "class", sourcePropertyOf = SourcePropertyOf.constructedInstance), @MOConstructorArg(sourceProperty = "size", sourcePropertyOf = SourcePropertyOf.constructedInstance) }) public List<Shape> getShapes() { return shapes; }
MOConstructorArg
,
MOInitializerProperty
,
SourcePropertyOf
Optional Element Summary | |
---|---|
MOConstructorArg[] |
constructorArgs
defines what parameter values to use when calling the constructor / factory. |
java.lang.Class |
factoryClass
the factory class. if not specified, the annotated class is assumed to be the factory class |
java.lang.String |
factoryMethod
the factory method name. |
MOInitializerProperty[] |
InitializerProperties
defines what properties of the bean to initialize and from what source right after creating an instance of the bean. |
public abstract MOConstructorArg[] constructorArgs
public abstract MOInitializerProperty[] InitializerProperties
public abstract java.lang.Class factoryClass
public abstract java.lang.String factoryMethod
constructorArgs()
member.
|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: REQUIRED | OPTIONAL | DETAIL: ELEMENT |