@JsonSerialize和JsonSerializer的用法

时间:2011-08-08 21:18:52

标签: spring-mvc jackson

问题

我有一个Spring MVC应用程序,它要求我将特定实体列表的id和名称转换为具有特定格式的JSON对象数组,并在特定请求中输出。也就是说,我需要一个像这样的JSON对象数组:

{
     label: Subject.getId()
     value: Subject.getName()
}

使用jQuery Autocomplete插件轻松使用。

所以在我的控制器中,我写了以下内容:

@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();
    }

}

然而,我回来的JSON是Jackson推断的默认序列化。我的自定义序列化程序似乎完全被忽略了。显然问题是@JsonSerialize或JsonSerializer的使用不正确,但我无法在任何地方找到这些内容的正确用法。

问题

使用Jackson实现我想要的序列化的正确方法是什么?请注意,在此上下文中以这种方式序列化实体非常重要,并且在其他位置打开其他序列化

2 个答案:

答案 0 :(得分:8)

@JsonSerialize应该在被序列化的类而不是控制器上设置。

答案 1 :(得分:0)

  

@JsonSerialize应该在要序列化的类而不是控制器上设置。

我想在上述答案中加上我的2美分(一个用例示例)...您不能总是为特定类型指定json序列化器,特别是在这是通用类型的情况下(确保不会允许在运行时为特定的泛型选择序列化程序),但是您始终可以创建一个新类型(您可以扩展广义类型,或者如果序列化类型是final且不能扩展,则可以创建包装器),并为这种类型。例如,您可以执行以下操作来序列化不同的org.springframework.data.domain.Page类型:

@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);
    }
}

然后您可以从服务的方法中返回您的类型-明确使用必要的序列化器:

@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());
    }
}