Estou tendo o seguinte problema. Tenho uma entidade que possui chave composta. Segui a linha do JPA, criei uma sub-entidade pra armazenar essa chave composta. Porém o VRaptor não consegue fazer a conversão, e lança a seguinte exceção:
java.lang.IllegalArgumentException: Vraptor does not support this interface or abstract type: java.io.Serializable
at br.com.caelum.vraptor.http.ognl.GenericNullHandler.instantiate(GenericNullHandler.java:65)
at br.com.caelum.vraptor.http.ognl.ReflectionBasedNullHandler.nullPropertyValue(ReflectionBasedNullHandler.java:79)
at ognl.ASTProperty.getValueBody(ASTProperty.java:118)
at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
at ognl.SimpleNode.getValue(SimpleNode.java:236)
at ognl.ASTChain.setValueBody(ASTChain.java:222)
at ognl.SimpleNode.evaluateSetValueBody(SimpleNode.java:220)
at ognl.SimpleNode.setValue(SimpleNode.java:279)
at ognl.Ognl.setValue(Ognl.java:737)
at ognl.Ognl.setValue(Ognl.java:783)[/code]
Meu código tá assim:
[code]@Entity
public class OperationItem implements Identifiable<OperationItemPK> {
private static final long serialVersionUID = 1L;
@EmbeddedId
private OperationItemPK id;
@Version
private Long version;
@Column(nullable = false)
private Integer quantity;
//Getters e setters omitidos
}[/code]
[code]@Embeddable
public class OperationItemPK implements Serializable{
private static final long serialVersionUID = 1L;
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(nullable = false, name="material_id")
private Material material;
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(nullable = false, name="operation_id")
private Operation operation;
public OperationItemPK() {}
/**
* @param material
* @param operation
*/
public OperationItemPK(final Material material, final Operation operation) {
this.material = material;
this.operation = operation;
}
//Getters e setters omitidos
}
Sim, eu sei, garcia-jj. E a minha é!! Observe que a minha entidade também é, pois a interface Identifiable que criei estende Serializable também. Ao que parece, o problema é que ele se perde ao tentar definir o conversor. Imagino que tenha a ver com o mecanismo de generics (type erasure), mas é estranho que com tipos “normais” (String, Long, Integer) não ocorre o problema… e ele sequer chega a chamar meu conversor. Se alguém puder dar alguma luz sobre o problema, agradeço. Se precisar de mais informações, é só pedir.
o que pode estar acontecendo é pq sua interface Identifiable tem getter e setter pra Serializable… (mesmo que vc tenha o tipo genérico, no final fica só Serializable…)
e o ognl tenta instanciar a interface Serializable, e claramente não consegue…
faz um teste: sobrescreva os getters e setters da interface, passando os tipos certos e teste… vê se funciona e me conta
lucascs,
Empreguei uma solução mais simples, que resolveu o problema: instanciei a chave no momento da criação da entidade. Dessa forma, o campo não era null e o VRaptor não teve que instanciá-lo.
Vou fazer o teste que você sugeriu e digo o resultado… mas é estranho que no caso de chaves simples, como Long, ele tenha sido capaz de instanciar sem problemas.
o tipo Long ele sabe instanciar… o tipo Serializable não… o problema é que, por causa do generics, seu metodo recebia um serializable, que confundiu o OGNL
Então, o ponto é que nas outras classes eu também uso essa inferface, não deveria dar o mesmo problema? Por exemplo, a classe Operation ficou assim:
[code]@Entity
public class Operation implements Identifiable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
[...]
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
[/code]
Agora fica uma dúvida… pelo que entendo, o getId(), apesar de estar implementando o getId() da interface, na implementação ele tem como retorno o tipo genérico (Long nesse caso, OperationItemPK no outro), afinal o tipo de retorno da método implementado deve ser compatível com o da definição, mas não necessáriamente o mesmo tipo. Então o tipo de retorno do getId() era OperationItemPK, e não Serializable. Deu pra compreender? Nesse caso, a idéia de que o tipo genérico estaria “ocultando” o tipo correto cai por terra…
Entao voce tem dois metodos: um que recebe Long, e outro que recebe Serializable. O OGNL, creio que seja compativel com java de 19xx, deve estar pegando o metodo errado (seria facil de resolver evitando os Method que retornam true no isBridge).
Muito bom saber isso. Eu não tinha essa idéia que ele construia duas versões do método. Nessa caso a solução mais simples é continuar instanciando o objeto antecipadamente.