Usage of @JsonSerialize and JsonSerializer
Problem
I have a Spring MVC application that requires me to translate the id's and names of a list of a certain entity to an array of JSON objects with specific formatting, and output that on a certain request. That is, I need an array of JSON objects like this:
{
label: Subject.getId()
value: Subject.getName()
}
For easy use with the jQuery Autocomplete plugin.
So in my controller, I wrote the following:
@RequestMapping(value = "/autocomplete.json", method = RequestMethod.GET)
@JsonSerialize(contentUsing=SubjectAutocompleteSerializer.class)
public @ResponseBody List<Subject> autocompleteJson() {
return Subject.findAllSubjects();
}
// Internal class
public class SubjectAutocompleteSerializer extends JsonSerializer<Subject> {
@Override
public void serialize(Subject value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeStartObject();
jgen.writeStringField("label", value.getId().toString());
jgen.writeStringField("value", value.getName());
jgen.writeEndObject();
}
}
The JSON I get back however, is the default serialization inferred by Jackson. My custom serializer seems to be completely ignored. Obviously the problem is incorrect usage of @JsonSerialize or JsonSerializer, 开发者_JAVA百科but I could not find proper usage of these within context anywhere.
Question
What is the proper way to use Jackson to achieve the serialization I want? Please note that it's important that the entities are only serialized this way in this context, and open to other serialization elsewhere
@JsonSerialize
should be set on the class that's being serialized not the controller.
@JsonSerialize should be set on the class that's being serialized not the controller.
I'd like to add my two cents (a use case example) to the above answer... You can't always specify a json serializer for a particular type especially if this is a generic type (erasure doesn't allow to pick the the serializer for a particular generic at runtime), however you can always create a new type (you can extend the generalized type or create a wrapper if the serialized type is final and can't be extended) and custom JsonSerializer for that type. For example you can do something like this to serialize different org.springframework.data.domain.Page types:
@JsonComponent
public class PageOfMyDtosSerializer
extends JsonSerializer<Page<MyDto>> {
@Override
public void serialize(Page<MyDto> page,
JsonGenerator jsonGenerator,
SerializerProvider serializerProvider)
throws IOException {
//...serialization logic for Page<MyDto> type
}
}
@JsonSerialize(using = PageOfMyDtosSerializer.class)
public class PageOfMyDtos extends PageImpl<MyDto> {
public PageOfMyDtos(List<MyDto> content, Pageable pageable, long total) {
super(content, pageable, total);
}
}
And then you can return your type from methods of your services - the necessary serializer will be utilized unambiguously:
@Service
@Transactional
public class MyServiceImpl implements MyService {
...
@Override
public Page<UserProfileDto> searchForUsers(
Pageable pageable,
SearchCriteriaDto criteriaDto) {
//...some business logic
/*here you pass the necessary search Specification or something else...*/
final Page<Entity> entities = myEntityRepository.findAll(...);
/*here you goes the conversion logic of your choice...*/
final List<MyDto> content = modelMapper.map(entieis.getContent(), new TypeToken<List<MyDto>>(){}.getType());
/*and finally return your the your new type so it will be serialized with the jsonSerializer we have specified*/
return new PageOfMyDtos(content, pageable, entities.getTotalElements());
}
}
精彩评论