Wrapper/Adapter Serializable

Para gravarmos dados na sessão do usuário é necessário que as classes implementem a interface java.io.Serializable. Caso isso não ocorra, podemos ter erro com a exceção: NotSerializableException ou mal funcionamento da aplicação, principalmente se você estiver em ambiente clusterizado com replicação de sessão.

E isso se torna, um problema quando trabalhamos com a geração automática de clientes de Web Services, pois as classes são geradas sem “implements java.io.Serializable”. Portanto não podemos inserir essas classes no contexto de sessão. Uma solução é editar as classes geradas incluindo o “implements java.io.Serializable”. O problema dessa abordagem é que ao gerar novamente as classes (como por exemplo: alteração de endpoint, atualização de WSDL ou inclusão de política de segurança ou SOAP Handler), as classes com “implements java.io.Serializable” serão sobreescritas e essa solução perderá validade, sendo necessário alterar todas as classes novamente.

Uma boa alternativa para resolver esse problema é a criação de Wrappers serializáveis para classes não serializáveis. Com base nesse problema resolvi criar uma interaface auxiliar para obrigar a implementação da conversão entre o Wrapper e a classe alvo.

[sourcecode lang=”java”]
public interface Wrappable extends Serializable {
public void wrap(T objectToCopy);
public T unwrap();
}
[/sourcecode]

O método wrap é responsável por receber um objeto e copiar os atributos necessários e o unwrap reconstrói o objeto. Para fins de demonstração utilizaremos a seguinte classe:

[sourcecode lang=”java”]
public class Boo {
private String doo;
private int foo;

public Boo(String doo, int foo) {
super();
this.doo = doo;
this.foo = foo;
}
public String getDoo() {
return doo;
}
public void setDoo(String doo) {
this.doo = doo;
}
public int getFoo() {
return foo;
}
public void setFoo(int foo) {
this.foo = foo;
}
}
[/sourcecode]

Essa é uma classe não serializável. Para criar o Wrapper serializável correspondente é só implementar devidamente a interface:

[sourcecode lang=”java”]
public class BooWrapper implements Wrappable {

private static final long serialVersionUID = 201103151148L;

private String doo;
private int foo;

public BooWrapper(Boo object) {
wrap(object);
}

@Override
public void wrap(Boo objectToCopy) {
this.doo = objectToCopy.getDoo();
this.foo = objectToCopy.getFoo();
}

@Override
public Boo unwrap() {
return new Boo(doo, foo);
}
}
[/sourcecode]

Não é recomendado herdar a classe ou mesmo incluí-la como atributo pois como ela não é serializável e também pode conter atributos não serializáveis, o problema não será resolvido (se mesmo assim você quiser, pode marcá-la como transiente). Com base no exemplo acima, podemos utilizar o Wrapper como um Adapter e alterar nome dos atributos/métodos, inserir métodos auxiliares e inserir somente o necessário na sessão. Diminuindo o acoplamento entre a camada Web e a camada de serviços.

Uma outra possibilidade é criar um arquivo de personalização dos bindings do JAXB para ter suporte à Serializable: http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/1.6/jaxb/vendorCustomizations.html#serializable

Sobre: Thiago Galbiatti Vespa

Thiago Galbiatti Vespa é mestre em Ciências da Computação e Matemática Computacional pela USP e bacharel em Ciências da Computação pela UNESP. Coordenador de projetos do JavaNoroeste, membro do JCP (Java Community Process), consultor Oracle, arquiteto de software de empresas de médio e grande porte, palestrante de vários eventos e colaborador de projetos open source. Possui as certificações: Oracle Certified Master, Java EE 5 Enterprise Architect – Step 1, 2 and 3; Oracle WebCenter Portal 11g Certified Implementation Specialist; Oracle Service Oriented Architecture Infrastructure Implementation Certified Expert; Oracle Certified Professional, Java EE 5 Web Services Developer; Oracle Certified Expert, NetBeans Integrated Development Environment 6.1 Programmer; Oracle Certified Professional, Java Programmer; Oracle Certified Associate, Java SE 5/SE 6