Sessão serializável e explorável

Aproveitando o embalo do post: http://www.thiagovespa.com.br/blog/2011/03/31/violando-o-encapsulamento/ resolvi criar uma aplicação para explorar a sessão de uma aplicação Web e verificar quais atributos são Serializáveis ou não. Para quem já precisou rodar uma aplicação em cluster com replicação de sessão sabe que é fundamental que todos os atributos que estão na sessão implemente a interface Serializable. Caso contrário, o erro NotSerializableException irá ocorrer.

Infelizmente existem bibliotecas de terceiros e de frameworks que não temos o código e nem documentação suficiente para saber se o atributo é serializável ou não, mas felizmente, temos maneiras de verificar isso utilizando código. Para resolver esse problema criei uma servlet que permiti navegarmos nas classes utilizadas nos atributos de sessão e explorar o conteúdo dos objetos.

Para recuperar as informações das classes, utilizei um map que associa a classe com suas informações. Nesse map estarão todas as classes envolvidas, seja por herança (linha 14) ou por composição (linha 17).

[sourcecode language=”java” highlight=”14,17″]
public void getAllFields(Class c, String fieldName) {
if (mapOfClasses.containsKey(c)) {
return;
}
Field[] fields = c.getDeclaredFields();
List fieldInfoList = new ArrayList();
for (Field f : fields) {
f.setAccessible(true);
fieldInfoList.add(new FieldInfo(f.getName(), f.getType(), f
.getModifiers()));
}
mapOfClasses.put(c, fieldInfoList);
if (c.getSuperclass() != null) {
getAllFields(c.getSuperclass(), "extends");
}
for (FieldInfo aFieldInfo : fieldInfoList) {
getAllFields(aFieldInfo.getFieldClass(), aFieldInfo.getFieldName());
}
}
[/sourcecode]

Esse método é chamado recursivamente para todos os tipos de atributos e para a classe pai. Dessa forma, o map fica composto por todas as classes envolvidas na sessão Web. Essas informações são auxiliares para verificar quais classes implementam a interface Serializable, e quais são os atributos envolvidos e se eles implementam também.

Os recursos mais bacanas implementados foram: navegar pelos atributos de sessão, calcular o tamanho que cada atributo fica em memória (isso permite análise para otimização de uso de sessão) e verificar quais atributos são serializáveis de maneira interativa. E para isso necessitamos verificar se o objeto é serializável ou não. Com isso seria necessário verificar se todos os seus atributos (não estáticos e blabla :D) acessíveis  são serializáveis, se a classe pai não for serializável, ela tem que ter um construtor padrão, entre outros. Existem vários aspectos a serem verificados. Mais informações você pode encontrar no próprio javadoc da interface Serializable. Para facilitar essa análise e realizá-la de maneira mais simples, basta serializar o objeto :D. Se tivermos um NotSerializableException significa que a classe não é serializável, caso contrário ela é serializável e como já serializamos ela, podemos recuperar o tamanho que ficará em memória. Podemos fazer isso utilizando um ByteArrayOutputStream e gravar o objeto nele. O código é bem simples:

[sourcecode language=”java”]
public int getSerialSize(Object o) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream oos;
oos = new ObjectOutputStream(out);
oos.writeObject(o);
oos.close();
return out.toByteArray().length;
}
[/sourcecode]

Dessa maneira fica muito simples analisar os objetos na sessão. Coloquei algumas cores para sinalizar cada objeto e o resultado final é o seguinte:

Session Serializable Checker
Session Serializable Checker

Dessa forma sabemos que o objeto da classe LocaleMB não é serializável. Podemos clicar no nome da classe para verificar quais atributos estão envolvidos e se ela implementa a interface serializable conforme mostrado abaixo:

Session Serializable Checker - 2
Session Serializable Checker - 2

Como podemos ver, a classe não está em amarelo, o que significa que ela implementa a interface Serializable, e podemos ver que apenas colocando implements Serializable não resolve o nosso problema. Se navegarmos dentro dos valores do objeto iremos ver algo interessante:

Session Serializable Checker - 3
Session Serializable Checker - 3

Embora a classe implemente a interface Serializable, um dos seus atributos não é serializável. Só conseguimos ver essa informação de maneira simples, graças a esse utilitário. E por isso vou disponibilizá-lo, caso alguém tenha problemas de NotSerializableException.

Para colocá-lo no seu projeto Web é muito simples. Copie o jar desse projeto para a pasta WEB-INF/lib (ou bibliotecas, build path, depende da IDE de sua preferência). Se o seu projeto utilizar Servlet 3.0, não é necessária nenhuma configuração adicional, pois ele já possui o mapeamento para Servlet  – @WebServlet(urlPatterns = { “/serialcheck” }). Caso você deseja sobreescrever esse mapeamento ou utiliza uma especificação de Servlet inferior, abra o seu arquivo web.xml e adicione as seguintes linhas:

[sourcecode language=”xml”]
…
<servlet>
<servlet-name>SerializableChecker</servlet-name>
<servlet-class>br.com.thiagovespa.serializablechecker.SerializableChecker</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SerializableChecker</servlet-name>
<url-pattern>/serialcheck</url-pattern>
</servlet-mapping>
…
[/sourcecode]

Aí é só acessar o endereço:  http[s]://<ip>:<porta>/<contexto>/serialcheck (p. ex: http://localhost:7001/portal/serialcheck) e brincar um pouco. Sugestões são bem vindas!

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