【问题标题】:Custom serializer for serializing a List<User> in List<String>用于序列化 List<String> 中的 List<User> 的自定义序列化程序
【发布时间】:2017-05-29 17:31:01
【问题描述】:

我有一个模型对象组

public class Group {
    String title;
    List<User> members;
    String createdBy;
}

我正在使用 Jackson 来序列化这个 Object。而不是序列化列表“成员”中的整个用户对象,我只想序列化 user.getTitle() 字段。 基本上我希望 HashMap 类似于

{
  "title" : "sometitle"
  "members" : [user1.getTitle(), user2.getTitle()]
}

我为此编写了一个自定义序列化程序

public class GroupSerializer extends JsonSerializer<Circle> {

    @Override
    public void serialize(Group value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {

        if(value != null) {
            gen.writeStartObject();
            gen.writeStringField("title", value.getTitle());
            gen.writeStringField("createdBy", value.getCreatedBy());
            gen.writeFieldName("members");
            gen.writeStartArray();
            for(User user : value.getMembers()) {
                gen.writeString(user.getEmail());
            }
            gen.writeEndArray();
            gen.writeEndObject()
        }
   }
}

但它不起作用。如何只序列化 List 的一个字段而不是整个 User Object?

【问题讨论】:

    标签: java android serialization jackson


    【解决方案1】:

    尝试如下:

    组:

    @JsonIgnoreProperties(ignoreUnknown=true)
    public class Group {
    
        @JsonSerialize(using= TitleSerializer.class)    
        List<User> members;
    
       //getters and setters 
    }
    

    用户:

    public class User {
    
        private String title;
    
        //getters and setters
    }
    

    自定义序列化器:

    public class TitleSerializer extends StdSerializer<List<User>> {
    
    
        private static List<User> users=new ArrayList<User>();
    
        protected TitleSerializer(Class<List<User>> t) {
            super(t);
            // TODO Auto-generated constructor stub
        }
    
        @SuppressWarnings("unchecked")
        public TitleSerializer(){
              this((Class<List<User>>) users.getClass());     
    
        }
    
        @Override
        public void serialize(List<User> users, JsonGenerator paramJsonGenerator,
                SerializerProvider paramSerializerProvider) throws IOException {
    
            paramJsonGenerator.writeStartObject();
            List<String> titles=new ArrayList<String>(users.size());
            for(User user: users){
                titles.add(user.getTitle());
            }
            paramJsonGenerator.writeObjectField("members", titles);
            paramJsonGenerator.writeEndObject();
        }
    
    }
    

    测试:

    Group group=new Group(Arrays.asList(new User("a"),new User("b"),new User("c")));
    ObjectMapper mapper = new ObjectMapper();       
    String serialized = mapper.writeValueAsString(group);
    System.out.println("output "+serialized);
    

    输出:

    {"members":["a","b","c"]}
    

    【讨论】:

    • 我很好奇为什么这不是公认的答案,或者至少为什么它被否决了。这似乎正是我们所需要的。
    • 因为这不起作用。不要在这个答案上浪费你的时间。输出为:输出 {"members":{"members":["a","b","c"]}}
    【解决方案2】:

    我建议您查看 Jackson 的 Converter 接口,它似乎比创建自定义序列化程序更适合该任务。

    一种方法是创建一个Converter 实例并将其添加到ObjectMapper,以便它将用于所有User 实例的序列化。

    public class UserConverter extends StdConverter<User, String> {
        @Override
        public String convert(User user) {
            return user.getTitle();
        }
    }
    

    在您的ObjectMapper 上注册,如下所示:

    SimpleModule simpleModule = new SimpleModule();
    simpleModule.addSerializer(User.class, new StdDelegatingSerializer(new UserConverter()));
    
    ObjectMapper om = new ObjectMapper().registerModule(simpleModule);
    

    如果您不想将所有 User 实例转换为 String,另一种方法是使用如下转换器注释选定的属性:

    public class Group {
        String title;
        @JsonSerialize(converter = ListUserConverter.class)
        List<User> members;
        String createdBy;
    }
    

    并且有一个对应的转换器,看起来像这样:

    public class ListUserConverter extends StdConverter<List<User>, List<String>> {
        @Override
        public List<String> convert(List<User> users) {
            return users.stream().map(User::getTitle).collect(Collectors.toList());
        }
    }
    

    【讨论】:

    • 这就是我要找的。谢谢。但是那个 stream() 函数是什么?
    • 很高兴听到这个消息! :) stream() 是 Java 8 的东西 (Read more),不是强制性的。随意按照您通常的方式转换列表。
    • 类似于 RxJava Observable。多谢,伙计。你的解决方案奏效了。
    • 我用它来过滤使用元素属性 (isHidden()) 的列表,因为 Jackson 2.8 没有 JsonInclude.Include.CUSTOM 功能,它已合并到 2.9 中。
    • 从 Jackson 2.2 开始,您还可以将 @JsonSerialize(contentConverter=UserConverter.class) 用于 List&lt;User&gt; 字段。这样,您可以为 User 字段或 List&lt;User&gt; 字段使用单个转换器类。
    猜你喜欢
    • 2016-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-09
    • 1970-01-01
    • 2014-02-08
    • 2013-09-23
    相关资源
    最近更新 更多