O mapeamento de polimorfismo, introduzido na versão 2.0, é uma solução que permite a um entidade ser mapeada para mais de um tipo. É implementado com a anotação @Any. Este tipo de mapeamento requer que, além do mapeamento da entidade, seja informado o metabean, uma variável que contém o identificador da entidade associada. Pode ser usado em um bean nas propriedades ou nos argumentos de um construtor e em um controlador nas propriedades ou nos parâmetros de uma ação.
@Target({ElementType.METHOD,ElementType.PARAMETER,ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface Any { Basic metaBean() default @Basic; Class metaType() default String.class; EnumerationType metaEnumerated() default EnumerationType.ORDINAL; String metaTemporal() default BrutosConstants.DEFAULT_TEMPORALPROPERTY; MetaValue[] metaValues() default {}; Class metaValuesDefinition() default MetaValuesDefinition.class; }
- metaBean(): variável que contém os metadados.
- metaType(): tipo da variável que contém os metadados.
- metaEnumerated(): usado quando o metadado for uma enumeração.
- metaTemporal(): usado quando o metadado for uma data.
- metaValues(): associa um valor a um bean.
- metaValuesDefinition(): Permite em tempo de execução associar um valor a um bean.
Abaixo um exemplo de uso da anotação @Any em uma propriedade de um bean.
public class TestBean{ @Basic(bean="property") @Any( metaBean=@Basic(bean="property_type") metaValues={ @MetaValue(name="Decimal", target=DecimalProperty.class), @MetaValue(name="Set", target=SetProperty.class) } ) private Property property ... }
Abaixo um exemplo de uso da anotação @Any em um construtor de um bean.
public class TestBean{ public TestBean( @Basic(bean="property") @Any( metaBean=@Basic(bean="property_type") metaValues={ @MetaValue(name="Decimal", target=DecimalProperty.class), @MetaValue(name="Set", target=SetProperty.class) } ) Property property){ ... } }
Abaixo um exemplo de uso da anotação @Any em uma propriedade de um controlador.
@Controller("/test") public class TestController{ @Basic(bean="property") @Any( metaBean=@Basic(bean="property_type") metaValues={ @MetaValue(name="Decimal", target=DecimalProperty.class), @MetaValue(name="Set", target=SetProperty.class) } ) private Property property ... }
Abaixo um exemplo de uso da anotação @Any em uma ação.
@Controller("/test") public class TestController{ @Action("/") public void testAction( @Basic(bean="property") @Any( metaBean=@Basic(bean="property_type") metaValues={ @MetaValue(name="Decimal", target=DecimalProperty.class), @MetaValue(name="Set", target=SetProperty.class) } ) Property property){ ... } }
Um exemplo da vida real seria um cenário de venda, onde um operador turístico vende diferentes serviços.
O exemplo irá permitir registrar um serviço aéreo ou de hospedagem por transação.
Dowload link: http://sourceforge.net/projects/brutos/files/brutos/2.0/examples/2.0-RC1/polymorphic-mapping.zip/download
Source code: http://sourceforge.net/p/brutos/code/HEAD/tree/trunk/examples/polymorphic-mapping/
Diagrama das entidades da aplicação.
Durante cada transação de venda, apenas um serviço será vendido. Podendo ser um serviço de hospedagem ou aéreo.
Classes
public class SaleTransaction { private Long id; @Transient private Date date; private Long price; @Any( metaBean = @Basic(bean = "serviceType"), metaType= String.class, metaValues = { @MetaValue(name = "air", target = AirService.class), @MetaValue(name = "hosting", target = HostingService.class) } ) private Service service; //gets e sets ... }
SaleTransaction.java
A anotação @Any indica que a propriedade service receberá uma instâncias da AirService, se o parâmetro serviceType for igual a "air", ou HostingServices, se o parâmetro serviceType for igual a "hosting".
public interface Service { void setPrice(Long value); Long getPrice(); String getServiceType(); }
Service.java
public abstract class AbstractService implements Service{ protected Long price; public void setPrice(Long value) { this.price = value; } public Long getPrice() { return this.price; } }
AbstractService.java
public class AirService extends AbstractService{ private String airplane; private String seat; @Temporal("yyyy-MM-dd hh:mm") private Date departureDate; @Temporal("yyyy-MM-dd hh:mm") private Date arrivalDate; public String getAirplane() { return airplane; } //gets e sets ... }
AirService.java
public class HostingService extends AbstractService{ private String hotel; @Temporal("yyyy-MM-dd") private Date checkin; @Temporal("yyyy-MM-dd") private Date checkout; private String mealPlan; private String room; //gets e sets ... }
HostingService.java
@Controller("/sales") @Action(value="/new", view=@View("new")) @RequestScoped public class SalesController { @Inject @Transient private SalesMemoryEntityAccess salesMemoryEntityAccess; @Action("/save") @Result("entity") public SaleTransaction save(@Basic(bean="entity") SaleTransaction entity){ this.salesMemoryEntityAccess.save(entity); return entity; } ... }
SalesController.java
View
<form method="POST" action="${pageContext.servletContext.contextPath}/sales/save"> <table> <tbody> <tr> <td>Id</td> <td>${entity.id}</td> </tr> <tr> <td>Price</td> <td><input type="text" name="entity.price" value="${entity.price}"></td> </tr> <tr> <td>Service type</td> <!-- campo do metaBean serviceType --> <td><select id="serviceType" name="entity.service.serviceType" onchange="javascript:showServiceDataundefined)"> <option ${entity.service.serviceType == 'air'? "selected " : ""} value="air">Air</option> <option ${entity.service.serviceType == 'hosting'? "selected " : ""} value="hosting">Hosting</option> </select></td> </tr> <!-- inicio do formulário do serviço aéreo --> <tr id="air"> <td> <table width="100%"> <tbody> <tr> <td>Airplane</td> <td><input type="text" name="entity.service.airplane" value="${entity.service.serviceType != 'air'? null : entity.service.airplane}"></td> </tr> <tr> <td>Departure date</td> <td><input type="text" name="entity.service.departureDate" value="<fmt:formatDate value="${entity.service.serviceType != 'air'? null : entity.service.departureDate}" pattern="yyyy-MM-dd hh:mm" />"></td> </tr> <tr> <td>Arrival date</td> <td><input type="text" name="entity.service.arrivalDate" value="<fmt:formatDate value="${entity.service.serviceType != 'air'? null : entity.service.arrivalDate}" pattern="yyyy-MM-dd hh:mm" />"></td> </tr> </tbody> </table> </td> </tr> <!-- inicio do formulário do serviço de hospedagem --> <tr id="hosting"> <td> <table width="100%"> <tbody> <tr> <td>Hotel</td> <td><input type="text" name="entity.service.hotel" value="${entity.service.serviceType != 'hosting'? null : entity.service.hotel}"></td> </tr> <tr> <td>Checkin</td> <td><input type="text" name="entity.service.checkin" value="<fmt:formatDate value="${entity.service.serviceType != 'hosting'? null : entity.service.checkin}" pattern="yyyy-MM-dd" />"></td> </tr> <tr> <td>Checkout</td> <td><input type="text" name="entity.service.checkout" value="<fmt:formatDate value="${entity.service.serviceType != 'hosting'? null : entity.service.checkout}" pattern="yyyy-MM-dd" />"></td> </tr> <tr> <td>Mealplan</td> <td><input type="text" name="entity.service.mealPlan" value="${entity.service.serviceType != 'hosting'? null : entity.service.mealPlan}"></td> </tr> <tr> <td>Room</td> <td><input type="text" name="entity.service.room" value="${entity.service.serviceType != 'hosting'? null : entity.service.room}"></td> </tr> </tbody> </table> </td> </tr> </tbody> <tfoot> <tr> <td><c:if test="${!empty entity.id}"> <input type="hidden" name="entity.id" value="${entity.id}"> </c:if> <input type="submit" value="Submit"></td> </tr> </tfoot> </table> </form>
http://www.brutosframework.com.br/
Nenhum comentário:
Postar um comentário