自定义序列化程序,将List<User>序列化为List<String>

8

我有一个Model对象组

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

我将使用Jackson来序列化这个对象。而不是将整个User对象序列化到列表“members”中,我只想序列化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对象?
2个回答

23
我建议您查看Jackson的转换器接口,它似乎比创建自定义序列化程序更适合此任务。
一种方法是创建一个转换器实例并将其添加到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()函数是什么? - crysis
很高兴听到这个消息! :) stream() 是 Java 8 的一个特性(阅读更多),并不是强制的。您可以按照自己通常的方式转换列表。 - Henrik Aasted Sørensen
1
这类似于RxJava Observable。谢谢,老兄。你的解决方案有效。 - crysis
我使用这个方法来过滤一个列表,使用元素的属性(isHidden())。由于Jackson 2.8没有JsonInclude.Include.CUSTOM功能,它被纳入了2.9版本中。 - tete
1
自Jackson 2.2以来,您还可以使用@JsonSerialize(contentConverter=UserConverter.class)来处理List<User>字段。这样,您就可以为User字段或List<User>字段使用单个转换器类。 - Alessandro Scarlatti

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"]}

我很好奇为什么这不是被接受的答案,或者至少为什么它被投票否决了。这似乎正是所需的。 - Andrew T Finnell
2
因为这个不起作用。不要浪费时间在这个答案上。输出是:output {"members":{"members":["a","b","c"]}}。 - mzl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接