terça-feira, 21 de julho de 2015

Mapeamento de polimorfismo com @Any no Brutos MVC

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 linkhttp://sourceforge.net/projects/brutos/files/brutos/2.0/examples/2.0-RC1/polymorphic-mapping.zip/download

Source codehttp://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