O formato JSON (JavaScript Object Notation) é uma escolha comum para a troca de dados em sistemas modernos. Sua estrutura leve e hierárquica facilita a leitura e escrita por humanos, ao mesmo tempo que permite que máquinas o analisem e gerem de forma eficiente, contribuindo para a otimização da comunicação em rede.
Em ambientes Java, onde a manipulação de dados ocorre predominantemente através de objetos, a conversão entre objetos Java e JSON é uma necessidade constante. Bibliotecas de serialização e desserialização de JSON preenchem essa lacuna, permitindo que objetos sejam transformados em representações JSON para transmissão e vice-versa, independentemente da linguagem de programação do consumidor.
Entre as diversas opções disponíveis, o Fastjson da Alibaba se destaca. Esta biblioteca de código aberto para Java oferece um conjunto robusto de ferramentas para converter objetos Java em cadeias de caracteres JSON e vice-versa. Fastjson é capaz de processar qualquer objeto Java, incluindo aqueles de bibliotecas de terceiros sem acesso ao código-fonte.
O que é Fastjson?
Fastjson é a biblioteca de serialização e desserialização de JSON da Alibaba. Ela converte dados em formato JSON para objetos Java (JavaBeans) e também permite a serialização de JavaBeans para representações JSON.
Benefícios do Fastjson
- Performance Excepcional: Fastjson é reconhecido por sua velocidade superior em comparação com outras bibliotecas JSON para Java, mantendo sua liderança em desempenho desde seu lançamento em 2011.
- Ampla Adoção: Utilizado extensivamente pela Alibaba em dezenas de milhares de servidores, Fastjson é uma solução amplamente aceita na indústria. Foi inclusive eleito um dos softwares de código aberto mais populares na China em 2012.
- Rigorosamente Testado: A biblioteca possui uma vasta suíte de testes, com mais de 3321 casos na versão 1.2.11. Cada lançamento passa por testes de regressão completos para garantir a estabilidade e a qualidade.
- Interface Simplificada: A API do Fastjson é intuitiva e fácil de usar.
- Funcionalidades Completas: Suporte a tipos genéricos, processamento de streams para grandes volumes de texto, enumerações e extensões para serialização e desserialização.
Como Obter o Fastjson
Fastjson está disponível para download e inclusão em projetos Java:
- Repositório Central Maven: http://central.maven.org/maven2/com/alibaba/fastjson/
- Sourceforge.net: https://sourceforge.net/projects/fastjson/files/
- Adicionando a dependência diretamente ao arquivo
pom.xmlde seu projeto Maven:
As versões mais recentes do Fastjson são publicadas no repositório central Maven. Recomenda-se utilizar a versão mais atualizada.
<dependency>
<groupId>com.alibaba>/groupId>
<artifactId>fastjson</artifactId>
<version>x.x.x</version>
</dependency>
Substitua x.x.x pelo número da versão desejada.
Principais APIs do Fastjson
A classe central para interagir com o Fastjson é com.alibaba.fastjson.JSON. Os métodos mais utilizados são JSON.toJSONString para serialização e JSON.parseObject para desserialização.
package com.alibaba.fastjson;
import java.io.Serializable; // Exemplo de interface, mantendo a abstração
public abstract class JSON implements Serializable { // Modificação sutil para a declaração
// Converte um objeto Java em uma string JSON
public static final String toJSONString(Object dataObject);
// Converte uma string JSON em um objeto Java do tipo especificado
public static final <T> T parseObject(String jsonText, Class<T> targetClass, Feature... parsingFeatures);
}
Exemplo de Serialização:
String serializedData = JSON.toJSONString(myJavaObject);
Exemplo de Desserialização:
MyValueObject resultObject = JSON.parseObject(jsonInputString, MyValueObject.class);
Desserialização com Tipos Genéricos:
import com.alibaba.fastjson.TypeReference;
import java.util.List;
List<MyValueObject> objectList = JSON.parseObject(jsonArrayString, new TypeReference<List<MyValueObject>>() {});
Desempenho do Fastjson
Fastjson é amplamente considerado a biblioteca JSON mais rápida para a linguagem Java, superando até mesmo alternativas como Jackson. Resultados de testes independentes estão disponíveis em: https://github.com/eishay/jvm-serializers/wiki.
Ao realizar seus próprios testes de dseempenho, é crucial desativar a detecção de referência circular para obter resultados precisos:
String jsonWithDisabledRefDetect = JSON.toJSONString(myObject, SerializerFeature.DisableCircularReferenceDetect);
MyObject deserializedObject = JSON.parseObject(jsonString, MyObject.class, Feature.DisableCircularReferenceDetect);
Adicionalmente, Fastjson demonstrou ser aproximadamente 6 vezes mais rápido que Gson em certos cenários. Abaixo, um fragmento de resultados de benchmarking para referência:
Checking correctness…
[done]
Pre-warmup… java-built-in hessian kryo protostuff-runtime avro-generic msgpack json/jackson/databind json/jackson/databind-strings json/jackson/db-afterburner json/google-gson/databind json/svenson-databind json/flexjson/databind json/fastjson/databind smile/jackson/databind smile/jackson/db-afterburner smile/protostuff-runtime bson/jackson/databind xml/xstream+c xml/jackson/databind-aalto
[done]
pre. create ser deser shal +deep total size +dfl
java-built-in 63 5523 27765 28084 28162 33686 889 514
hessian 64 3776 6459 6505 6690 10466 501 313
kryo 63 809 962 937 1001 1810 214 133
protostuff-runtime 62 671 903 920 957 1627 241 151
avro-generic 436 1234 1122 1416 1760 2994 221 133
msgpack 61 789 1369 1385 1449 2238 233 146
json/jackson/databind 60 1772 3089 3113 3246 5018 485 261
json/jackson/databind-strings 64 2346 3739 3791 3921 6267 485 261
json/jackson/db-afterburner 64 1482 2220 2233 2323 3805 485 261
json/google-gson/databind 64 7076 4894 4962 5000 12076 486 259
json/svenson-databind 64 5422 12387 12569 12468 17890 495 266
json/flexjson/databind 62 20923 26853 26873 27272 48195 503 273
json/fastjson/databind 63 1250 1208 1206 1247 2497 486 262
smile/jackson/databind 60 1697 2117 2290 2298 3996 338 241
smile/jackson/db-afterburner 60 1300 1614 1648 1703 3003 352 252
smile/protostuff-runtime 61 1275 1612 1638 1685 2961 335 235
bson/jackson/databind 63 5151 6729 6977 6918 12069 506 286
xml/xstreamc 62 6358 13208 13319 13516 19874 487 244
xml/jackson/databind-aalto 62 2955 5332 5465 5584 8539 683 286
Exemplo de Uso do Fastjson
Considere a modelagem de uma turma e seus respectivos alunos:
Objeto Turma (SchoolClass):
import java.util.ArrayList;
import java.util.List;
public class SchoolClass {
private Long identifier;
private String className;
private List<StudentEntry> students = new ArrayList<>();
// Construtores, getters e setters
public Long getIdentifier() { return identifier; }
public void setIdentifier(Long identifier) { this.identifier = identifier; }
public String getClassName() { return className; }
public void setClassName(String className) { this.className = className; }
public List<StudentEntry> getStudents() { return students; }
public void setStudents(List<StudentEntry> students) { this.students = students; }
public void addStudent(StudentEntry student) {
this.students.add(student);
}
@Override
public String toString() {
return "SchoolClass{" +
"identifier=" + identifier +
", className='" + className + '\'' +
", students=" + students +
'}';
}
}
Objeto Aluno (StudentEntry):
public class StudentEntry {
private Long studentId;
private String studentName;
// Construtores, getters e setters
public Long getStudentId() { return studentId; }
public void setStudentId(Long studentId) { this.studentId = studentId; }
public String getStudentName() { return studentName; }
public void setStudentName(String studentName) { this.studentName = studentName; }
@Override
public String toString() {
return "StudentEntry{" +
"studentId=" + studentId +
", studentName='" + studentName + '\'' +
'}';
}
}
Função Principal (AppRunner):
import com.alibaba.fastjson.JSON;
public class AppRunner {
public static void main(String[] args) {
SchoolClass myClass = new SchoolClass();
myClass.setIdentifier(101L);
myClass.setClassName("Matemática Avançada");
StudentEntry firstStudent = new StudentEntry();
firstStudent.setStudentId(1L);
firstStudent.setStudentName("Alice Silva");
StudentEntry secondStudent = new StudentEntry();
secondStudent.setStudentId(2L);
secondStudent.setStudentName("Bruno Costa");
myClass.addStudent(firstStudent);
myClass.addStudent(secondStudent);
// Serializa o objeto para JSON
String jsonOutput = JSON.toJSONString(myClass);
System.out.println("String JSON gerada: " + jsonOutput);
// Desserializa a string JSON de volta para um objeto Java
SchoolClass deserializedClass = JSON.parseObject(jsonOutput, SchoolClass.class);
System.out.println("Objeto Java reconstruído: " + deserializedClass);
}
}
Saída Esperada:
String JSON gerada: {"className":"Matemática Avançada","identifier":101,"students":[{"studentId":1,"studentName":"Alice Silva"},{"studentId":2,"studentName":"Bruno Costa"}]}
Objeto Java reconstruído: SchoolClass{identifier=101, className='Matemática Avançada', students=[StudentEntry{studentId=1, studentName='Alice Silva'}, StudentEntry{studentId=2, studentName='Bruno Costa'}]}
Gerenciamento de Valores Nulos no Fastjson
Por padrão, Fastjson omite valores nulos durante a serialização, seja em Maps ou em atributos de objetos, para reduzir o tamanho da representação JSON. Contudo, é possível configurar o Fastjson para incluir esses valores.
Para incluir explicitamente valores nulos, utilize a feature SerializerFeature.WriteMapNullValue:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
MyDataModel data = new MyDataModel(); // Supondo que 'data' tenha alguns campos nulos
String jsonWithNulls = JSON.toJSONString(data, SerializerFeature.WriteMapNullValue);
Fastjson oferece outras SerializerFeature para controle granular sobre a serialização de nulos em tipos específicos:
SerializerFeature |
Descrição |
|---|---|
WriteNullListAsEmpty |
Serializa campos de coleção com valor nulo como uma lista vazia []. |
WriteNullStringAsEmpty |
Serializa campos de string com valor nulo como uma string vazia "". |
WriteNullNumberAsZero |
Serializa campos numéricos com valor nulo como 0. |
WriteNullBooleanAsFalse |
Serializa campos booleanos com valor nulo como false. |
É possível combinar várias features, como no exemplo abaixo:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import java.util.List;
class ProductInventory {
public List<Object> productItems;
public String description;
public Integer stockAmount;
public Boolean available;
}
ProductInventory inventory = new ProductInventory(); // Assumindo alguns campos nulos
String outputJson = JSON.toJSONString(
inventory,
SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteNullNumberAsZero,
SerializerFeature.WriteNullBooleanAsFalse
);
Manipulação de Datas no Fastjson
Fastjson oferece métodos diretos para formatar datas durante a serialização.
Para formatar uma data específica:
import com.alibaba.fastjson.JSON;
import java.util.Date;
Date currentDate = new Date();
String formattedDate = JSON.toJSONStringWithDateFormat(currentDate, "yyyy-MM-dd HH:mm:ss.SSS");
Utilizando o formato de data ISO-8601:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
// Supondo um objeto 'event' com um campo Date
String isoFormattedJson = JSON.toJSONString(event, SerializerFeature.UseISO8601DateFormat);
Para uma alteração global do formato de data (afeta todos os objetos serializados, a menos que sobreposto):
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd"; // Define o formato padrão
// Supondo um objeto 'report' com campos Date
String customGlobalFormattedJson = JSON.toJSONString(report, SerializerFeature.WriteDateUseDateFormat);
Na desserialização, Fastjson é inteligente o suficiente para reconhecer e converter automaticamente uma variedade de formatos de data, incluindo:
- Formato de data ISO-8601
yyyy-MM-ddyyyy-MM-dd HH:mm:ssyyyy-MM-dd HH:mm:ss.SSS- Números representando milissegundos
- Strings de números representando milissegundos
- Formato de data JSON do .NET
new Date(198293238)
Para cenários onde campos de data dentro de um mesmo objeto requerem formatos distintos, a serialização personalizada é a solução ideal.
Serialização Personalizada com Fastjson
Fastjson oferece várias abordagens para personalizar o processo de serialização:
- Através da anotação
@JSONField. - Através da anotação
@JSONType. - Utilizando interfaces
SerializeFilter. - Utilizando interfaces
ParseProcesspara desserialização personalizada.
Personalização com @JSONField
1. Visão Geral da Anotação @JSONField
package com.alibaba.fastjson.annotation;
public @interface JSONField {
// Ordem de serialização e desserialização (disponível a partir da v1.1.42)
int ordinal() default 0;
// Nome do campo no JSON
String name() default "";
// Formato específico para campos de data/hora
String format() default "";
// Controla se o campo deve ser serializado
boolean serialize() default true;
// Controla se o campo deve ser desserializado
boolean deserialize() default true;
}
2. Aplicação da Anotação @JSONField
A anotação @JSONField pode ser aplicada em campos (fields) ou em métodos getter/setter.
Aplicando em campos:
import com.alibaba.fastjson.annotation.JSONField;
import java.util.Date;
public class UserDetails {
@JSONField(name="userID")
private int identifier;
@JSONField(name="birthDate", format="yyyy-MM-dd")
public Date registrationDate; // Mudança do nome do campo
}
Aplicando em métodos Getter/Setter:
import com.alibaba.fastjson.annotation.JSONField;
public class ProductItem {
private String productCode;
@JSONField(name="PROD_CODE")
public String getProductCode() { return productCode;}
@JSONField(name="PROD_CODE") // Anotação também no setter para desserialização
public void setProductCode(String productCode) {this.productCode = productCode;}
}
Observação: Se o atributo for privado, é essencial ter métodos
set*correspondentes para permitir a desserialização.
3. Usando format para Datas
Personalize o formato de datas para cada campo:
import com.alibaba.fastjson.annotation.JSONField;
import java.util.Date;
public class EventLog {
// Configura data para ser serializada/desserializada no formato 'yyyyMMdd'
@JSONField(format="yyyyMMdd")
public Date timestamp;
}
4. Usando serialize/deserialize para Excluir Campos
Controle a inclusão ou exclusão de campos na serialização ou desserialização:
import com.alibaba.fastjson.annotation.JSONField;
import java.util.Date;
public class SensitiveData {
@JSONField(serialize=false) // Este campo não será incluído na saída JSON
public Date creationTimestamp;
}
import com.alibaba.fastjson.annotation.JSONField;
import java.util.Date;
public class InputConfig {
@JSONField(deserialize=false) // Este campo será ignorado na entrada JSON
public Date lastModification;
}
5. Usando ordinal para Definir a Ordem dos Campos
Por padrão, Fastjson serializa campos em ordem alfabética. A partir da versão 1.1.42, ordinal permite definir a ordem de saída dos campos.
import com.alibaba.fastjson.annotation.JSONField;
public static class OrderedFields {
@JSONField(ordinal = 3)
private int fieldC; // Alteração do nome
@JSONField(ordinal = 2)
private int fieldB; // Alteração do nome
@JSONField(ordinal = 1)
private int fieldA; // Alteração do nome
// Getters e setters
public int getFieldC() { return fieldC; }
public void setFieldC(int fieldC) { this.fieldC = fieldC; }
public int getFieldB() { return fieldB; }
public void setFieldB(int fieldB) { this.fieldB = fieldB; }
public int getFieldA() { return fieldA; }
public void setFieldA(int fieldA) { this.fieldA = fieldA; }
}
6. Usando serializeUsing com um Serializador Personalizado
A partir da versão 1.2.16, @JSONField suporta serializeUsing para aplicar um serializador específico a um atributo de uma classe. Isso permite personalizar a representação JSON de um valor específico.
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.ObjectSerializer;
import java.io.IOException;
import java.lang.reflect.Type;
public static class PriceInformation { // Alteração do nome da classe
@JSONField(serializeUsing = PriceValueSerializer.class)
public int finalPrice; // Alteração do nome do campo
}
public static class PriceValueSerializer implements ObjectSerializer { // Alteração do nome da classe
@Override
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,
int features) throws IOException {
Integer price = (Integer) object;
String formattedPrice = price + " EUR"; // Modificação do valor
serializer.write(formattedPrice);
}
}
Código de Teste:
import com.alibaba.fastjson.JSON;
import org.junit.Assert; // Assumindo JUnit para asserts
// ... classes PriceInformation e PriceValueSerializer definidas acima ...
public class SerializationTest {
public static void main(String[] args) {
PriceInformation itemPrice = new PriceInformation();
itemPrice.finalPrice = 250; // Novo valor
String jsonResult = JSON.toJSONString(itemPrice);
System.out.println(jsonResult);
Assert.assertEquals("{\"finalPrice\":\"250 EUR\"}", jsonResult);
}
}
Personalização com @JSONType
Similar a @JSONField, mas @JSONType é aplicada no nível da classe para configurações que afetam todo o objeto, não apenas um campo específico.
Serialização Personalizada com SerializeFilter
1. Introdução
SerializeFilter é uma abordagem programática para personalizar a serialização. Fastjson oferece seis tipos de SerializeFilter para diferentes cenários:
PropertyPreFilter: Decide serializar com base no nome da propriedade.PropertyFilter: Decide serializar com base no nome e valor da propriedade.NameFilter: Modifica o nome da chave (Key) na saída JSON.ValueFilter: Modifica o valor (Value) na saída JSON.BeforeFilter: Adiciona conteúdo antes da serialização dos atributos do objeto.AfterFilter: Adiciona conteúdo após a serialização dos atributos do objeto.
2. PropertyFilter: Filtragem por Nome e Valor da Propriedade
public interface PropertyFilter extends SerializeFilter {
boolean apply(Object sourceObject, String propertyKey, Object propertyValue);
}
Permite decidir a serialização com base no objeto, nome da propriedade ou valor da propriedade. Exemplo:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.PropertyFilter;
// ... Assumindo uma classe 'UserRecord' com um campo 'userId' (int)
PropertyFilter userFilter = new PropertyFilter() {
@Override
public boolean apply(Object sourceObject, String propertyKey, Object propertyValue) {
if ("userId".equals(propertyKey)) {
int userId = ((Integer) propertyValue).intValue();
return userId >= 1000; // Serializa apenas se userId for maior ou igual a 1000
}
return false; // Não serializa outras propriedades por padrão
}
};
// ... Criar um objeto UserRecord
// String filteredJson = JSON.toJSONString(userRecordObject, userFilter);
3. PropertyPreFilter: Filtragem Apenas por Nome da Propriedade
Diferente de PropertyFilter, este filtro age antes da chamada do getter, evitando possíveis exceções se o getter não for seguro.
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.PropertyPreFilter;
public interface PropertyPreFilter extends SerializeFilter {
boolean apply(JSONSerializer currentSerializer, Object sourceObject, String propertyName);
}
4. NameFilter: Modificação do Nome da Chave
Para alterar o nome das chaves (propriedades) no JSON de saída, o método process deve retornar o novo nome.
import com.alibaba.fastjson.serializer.NameFilter;
public interface NameFilter extends SerializeFilter {
String process(Object object, String propertyName, Object propertyValue);
}
Fastjson inclui um PascalNameFilter para converter nomes de campos para o estilo PascalCase (primeira letra maiúscula). Exemplo:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.PascalNameFilter;
// Supondo um objeto 'productDetails' com campos como 'productName'
String pascalCaseJson = JSON.toJSONString(productDetails, new PascalNameFilter());
// Saída: {"ProductName":"..."}, em vez de {"productName":"..."}
5. ValueFilter: Modificação do Valor
Permite interceptar e modificar os valores das propriedades antes da serialização.
import com.alibaba.fastjson.serializer.ValueFilter;
public interface ValueFilter extends SerializeFilter {
Object process(Object object, String propertyName, Object propertyValue);
}
6. BeforeFilter: Adicionar Conteúdo Antes
Executa ações ou adiciona pares chave-valor ao JSON antes de serializar as propriedades padrão do objeto.
import com.alibaba.fastjson.serializer.BeforeFilter;
public abstract class BeforeFilter implements SerializeFilter {
protected final void writeKeyValue(String key, Object value) { /* Implementação interna */ }
// Implemente este método abstrato para adicionar conteúdo via writeKeyValue
public abstract void writeBefore(Object object);
}
7. AfterFilter: Adicionar Conteúdo Depois
Executa ações ou adiciona pares chave-valor ao JSON depois de serializar as propriedades padrão do objeto.
import com.alibaba.fastjson.serializer.AfterFilter;
public abstract class AfterFilter implements SerializeFilter {
protected final void writeKeyValue(String key, Object value) { /* Implementação interna */ }
// Implemente este método abstrato para adicionar conteúdo via writeKeyValue
public abstract void writeAfter(Object object);
}
Desserialização Personalizada com ParseProcess
1. Introdução
ParseProcess fornece interfaces para estender e personalizar o processo de desserialização. Fastjson suporta:
ExtraProcessor: Lida com campos no JSON que não existem no objeto Java.ExtraTypeProvider: Fornece informações de tipo para campos extras.
2. Usando ExtraProcessor para Campos Adicionais
Quando o JSON de entrada contém campos que não mapeiam diretamente para propriedades de um objeto Java, ExtraProcessor pode capturá-los.
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.deserializer.ExtraProcessor;
import java.util.HashMap;
import java.util.Map;
public static class UserProfile { // Alteração do nome da classe
private int profileId; // Alteração do nome do campo
private Map<String, Object> extraProperties = new HashMap<>(); // Alteração do nome do campo
public int getProfileId() { return profileId; }
public void setProfileId(int profileId) { this.profileId = profileId;}
public Map<String, Object> getExtraProperties() { return extraProperties;}
}
ExtraProcessor customProcessor = new ExtraProcessor() {
@Override
public void processExtra(Object targetObject, String keyName, Object valueData) { // Alteração de nomes de parâmetros
UserProfile user = (UserProfile) targetObject;
user.getExtraProperties().put(keyName, valueData);
}
};
UserProfile userProfile = JSON.parseObject("{\"profileId\":456,\"userName\":\"John Doe\"}", UserProfile.class, customProcessor);
System.out.println("ID do perfil: " + userProfile.getProfileId());
System.out.println("Nome de usuário (extra): " + userProfile.getExtraProperties().get("userName"));
// Assert.assertEquals(456, userProfile.getProfileId());
// Assert.assertEquals("John Doe", userProfile.getExtraProperties().get("userName"));
3. Usando ExtraTypeProvider para Definir Tipos de Campos Extras
ExtraTypeProvider complementa ExtraProcessor, permitindo especificar o tipo Java para um campo extra, influenciando como o valor é desserializado.
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.deserializer.ExtraProcessor;
import com.alibaba.fastjson.parser.deserializer.ExtraTypeProvider;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
public static class ItemData { // Alteração do nome da classe
private int itemId; // Alteração do nome do campo
private Map<String, Object> auxiliaryData = new HashMap<>(); // Alteração do nome do campo
public int getItemId() { return itemId; }
public void setItemId(int itemId) { this.itemId = itemId;}
public Map<String, Object> getAuxiliaryData() { return auxiliaryData;}
}
class CustomItemProcessor implements ExtraProcessor, ExtraTypeProvider { // Alteração do nome da classe
@Override
public void processExtra(Object targetObject, String keyName, Object valueData) {
ItemData item = (ItemData) targetObject;
item.getAuxiliaryData().put(keyName, valueData);
}
@Override
public Type getExtraType(Object targetObject, String keyName) {
if ("itemQuantity".equals(keyName)) { // Alteração do nome do campo extra
return Integer.class; // Garante que "itemQuantity" seja desserializado como Integer
}
return null;
}
}
ExtraProcessor itemProcessor = new CustomItemProcessor();
ItemData product = JSON.parseObject("{\"itemId\":789,\"itemQuantity\":\"500\"}", ItemData.class, itemProcessor);
System.out.println("ID do item: " + product.getItemId());
System.out.println("Quantidade do item (convertida): " + product.getAuxiliaryData().get("itemQuantity"));
// Assert.assertEquals(789, product.getItemId());
// Assert.assertEquals(500, product.getAuxiliaryData().get("itemQuantity")); // Note a conversão para Integer
Integração do Fastjson com Spring MVC
Para aplicativos web que utilizam Spring MVC e exigem alta performance na serialização/desserialização JSON, o FastJsonHttpMessageConverter do Fastjson pode substituir o conversor padrão do Spring MVC. Isso otimiza a velocidade de processamento de JSON para anotações como @RestController, @ResponseBody e @RequestBody.
Configuração Baseada em XML:
Adicione a seguinte configuração ao arquivo XML do Spring MVC:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
Para configurações personalizadas, adicione um bean FastJsonConfig:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="fastJsonConfig" ref="customFastJsonConfig"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="customFastJsonConfig" class="com.alibaba.fastjson.support.config.FastJsonConfig">
<!-- Adicione suas configurações personalizadas aqui, ex: setDateFormat, setSerializerFeatures -->
</bean>
Configuração Programática (comum em Spring Boot):
Estenda WebMvcConfigurerAdapter (ou implemente WebMvcConfigurer a partir do Spring 5) e sobrescreva o método configureMessageConverters:
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; // Ou WebMvcConfigurer
import java.util.List;
@Configuration
public class WebConfigurationAdapter extends WebMvcConfigurerAdapter { // Renomeado
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
FastJsonHttpMessageConverter fastJsonConverter = new FastJsonHttpMessageConverter();
// Opcional: Configurações personalizadas
// FastJsonConfig customConfig = new FastJsonConfig();
// customConfig.set...
// fastJsonConverter.setFastJsonConfig(customConfig);
converters.add(0, fastJsonConverter); // Adiciona na primeira posição
}
}
Observações importantes:
1. Versões do Fastjson: Se estiver usando Fastjson com versão anterior a 1.2.36 (fortemente recomendado atualizar), e Spring MVC 4.X, use
FastJsonHttpMessageConverter4.2. Ordem dos Conversores no Spring Boot: No Spring Boot 2.0.1 e versões posteriores, a ordem de carregamento dos
WebMvcConfigurermudou. É crucial adicionar oFastJsonHttpMessageConverterna primeira posição (converters.add(0, converter)) para garantir que ele seja priorizado sobre o Jackson, que é o padrão.
Integração do Fastjson com Spring Data Redis
Para quem utiliza RedisTemplate do Spring Data Redis e necessita de alta performance na serialização/desserialização JSON, o Fastjson oferece GenericFastJsonRedisSerializer ou FastJsonRedisSerializer como alternativas para RedisSerializer.
Configuração Baseada em XML:
Substitua o Serializer padrão do RedisTemplate por GenericFastJsonRedisSerializer:
<bean id="redisOperationsTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <!-- Renomeado -->
<property name="connectionFactory" ref="jedisConnFactory"/> <!-- Renomeado -->
<property name="defaultSerializer">
<bean class="com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer"/>
</property>
</bean>
Exemplo de configuração completa para Spring com Redis:
<!-- Configuração do Pool de Conexões Redis (Opcional) -->
<bean id="jedisPoolConfigCustom" class="redis.clients.jedis.JedisPoolConfig"> <!-- Renomeado -->
<property name="maxTotal" value="${redis.pool.maxActive}"/>
<property name="maxIdle" value="${redis.pool.maxIdle}"/>
<property name="maxWaitMillis" value="${redis.pool.maxWait}"/>
<property name="testOnBorrow" value="${redis.pool.testOnBorrow}"/>
<!-- Outras configurações de pool... -->
</bean>
<!-- Configuração da Fábrica de Conexões Redis -->
<bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <!-- Renomeado -->
<!-- Define a configuração do pool; sem isso, o pool padrão é usado. Defina usePool = false para desativar. -->
<property name="poolConfig" ref="jedisPoolConfigCustom" />
<property name="hostName" value="${redis.host}"/> <!-- Variável renomeada -->
<property name="port" value="${redis.port}"/> <!-- Variável renomeada -->
<property name="password" value="${redis.password}"/> <!-- Variável renomeada -->
<property name="database" value="${redis.database}"/> <!-- Variável renomeada -->
<!-- Outras configurações da fábrica de conexões... -->
</bean>
<!-- Configuração do RedisTemplate -->
<bean id="redisOperationsTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <!-- Renomeado -->
<!-- Define a fábrica de conexões Redis -->
<property name="connectionFactory" ref="jedisConnFactory"/> <!-- Renomeado -->
<!-- Define o Serializer padrão, incluindo keySerializer e valueSerializer -->
<property name="defaultSerializer">
<bean class="com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer"/>
</property>
<!-- Opcional: Definição separada para keySerializer -->
<property name="keySerializer">
<bean class="com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer"/>
</property>
<!-- Opcional: Definição separada para valueSerializer -->
<property name="valueSerializer">
<bean class="com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer"/>
</property>
</bean>
Configuração Programática (comum em Spring Boot):
Crie um bean RedisTemplate explicitamente em uma classe de configuração (anotada com @Configuration) e defina o Serializer:
import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
@Configuration
public class RedisConfig { // Renomeado
@Bean
public RedisTemplate<String, Object> customRedisTemplate(RedisConnectionFactory redisConnectionFactory) { // Renomeado
RedisTemplate<String, Object> template = new RedisTemplate<>(); // Renomeado
template.setConnectionFactory(redisConnectionFactory);
GenericFastJsonRedisSerializer serializer = new GenericFastJsonRedisSerializer();
template.setDefaultSerializer(serializer); // Define o Serializer padrão (key e value)
// Opcional: Define keySerializer e valueSerializer separadamente
// template.setKeySerializer(serializer);
// template.setValueSerializer(serializer);
return template;
}
}
Normalmente, GenericFastJsonRedisSerializer é suficiente. Para tipos específicos, FastJsonRedisSerializer pode ser usado de maneira similar, permitindo maior controle sobre a serialização de tipos específicos de objetos no Redis.