Problema ao Intanciar Bean no VRaptor 3

9 respostas
D

Olá, pessoal.

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)
Meu código tá assim:
@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
}
@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
}
A interface que minhas entidades implementam:
public interface Identifiable<PK extends Serializable> extends Serializable {

	public PK getId();
	
	public void setId(final PK id);
	
}
Cheguei a fazer um converter, mas ele sequer é chamado:
@Convert(OperationItemPK.class)
@ApplicationScoped
public class OperationItemPKConverter implements Converter<OperationItemPK> {

	/**
	 * 
	 */
	public OperationItemPKConverter() {
		System.out.println("OperationItemPKConverter.OperationItemPKConverter()");
	}
	
	/* (non-Javadoc)
	 * @see br.com.caelum.vraptor.Converter#convert(java.lang.String, java.lang.Class, java.util.ResourceBundle)
	 */
	@Override
	public OperationItemPK convert(String value,
			Class<? extends OperationItemPK> type, ResourceBundle bundle) {
		System.out.println(value);
		return null;
	}

}

Alguma sugestão? Em último caso, vou adicionar acessores pros campos da PK diretamente na classe externa, fazendo delegação.

Atenciosamente.

9 Respostas

G

Toda e qualquer chave composta DEVE ser Serializable.

D

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.

T+

G

Poxa, desculpe, eu li correndo já saindo da empresa. Isso o lucas pode te responder melhor.

Abraços

Lucas_Cavalcanti

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 :wink:

D

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.

T+

Lucas_Cavalcanti

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

D

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:

@Entity
public class Operation implements Identifiable<Long> {

	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;
	}
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...

T+

Paulo_Silveira

Oi Duron!

Infelizmente pode ser o generics sim. O java 5 infelizmente enfia bridge methods dentro da classe por causa do generics:
http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#FAQ102

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).

D

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.

T+

Criado 14 de dezembro de 2009
Ultima resposta 16 de dez. de 2009
Respostas 9
Participantes 4