关于java:如何不将组合对象包含到json中?

How to not include composed object into json?

我有以下课程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Container{
    String description;
    Element1 element1;
    Element2 element2;
}

public class Element1{
    String f11;
    String f12;
}

public class Element2{
    String f21;
    String f22;
}

我将Container序列化为json格式。 对于json序列化我使用Jackson。

现在我希望如果f11f12f21f22f22,则不要将element1element2包含到json中。

正如我所说,我应该编写cistom序列化程序,但我不明白哪个实体。 ElementContainer? 如何 ?

附:

我的问题不是使用Jackson忽略JSON对象上的新字段

本主题解释了如何忽略Container内的空值。 我的问题是如何忽略Container里面只有空值的对象


受StaxMan答案启发的另一个想法是实现一个"空元素模块",它将Container的所有覆盖封装到Container中的不同元素中。例如,模块看起来像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class EmptyElementModule extends SimpleModule {
    private static final String NAME ="EmptyElementModule";

    public EmptyElementModule() {
        super(NAME);
        setSerializerModifier(new EmptyElementSerializerModifier());
    }

    public static class EmptyElementSerializerModifier extends BeanSerializerModifier {
        @Override
        public JsonSerializer< ? > modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer< ? > serializer) {
            Class< ? > beanClass = beanDesc.getBeanClass();
            if (beanClass == Element1.class) {
                return new EmptyElement1Serializer((JsonSerializer<Object>) serializer);
            } else if (beanClass == Element2.class) {
                // return element 2 serializer
            }
            return serializer;
        }
    }

    public static class EmptyElement1Serializer extends JsonSerializer<Element1> {
        private final JsonSerializer<Object> defaultSerializer;

        public EmptyElement1Serializer(JsonSerializer<Object> defaultSerializer) {
            this.defaultSerializer = checkNotNull(defaultSerializer);
        }

        @Override
        public void serialize(Element1 value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            defaultSerializer.serialize(value, gen, serializers);
        }

        @Override
        public boolean isEmpty(SerializerProvider provider, Element1 value) {
            return value.f11 == null && value.f12 == null;
        }
    }
}


虽然您可能确实需要自定义序列化程序,但是需要覆盖的方法是isEmpty(...);然后指定属性的包含策略,如下所示:

1
@JsonInclude(JsonInclude.Include.NON_EMPTY)

这将让"拥有"对象确定要避免序列化:否则将调用自定义序列化程序并且它必须写一个值 - 当然你可以编写null,但自定义序列化程序本身不能拒绝写任何东西,因为属性名称已由调用者编写。


要忽略容器中只有空/空成员(容器的成员,成员)的元素,您可以为Container创建自定义序列化程序。自定义序列化程序非常棒,因为它们可以最终控制对象的编写方式,但这也会导致代码难以维护。我之所以这么说是因为有了杰克逊,你可以用自定义的de / serializer完成任何事情,但对于大多数问题,通常都有一种更简洁的方式(例如通过注释)。为此,OP请求编写自定义序列化程序的指导,我不知道一种更简单的方法来完成所需的行为。

创建Module和自定义序列化程序

Jackson Module用于封装单个对象的反序列化器和序列化器。对于此示例,仅需要序列化程序,但如果要为Container添加解串器,则可以将其与ContainerModule内的序列化程序一起添加。以下代码定义Container的序列化程序,如果其成员中至少有一个非空,则只写element1element2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class ContainerModule extends SimpleModule {
    private static final String NAME ="ContainerModule";

    public ContainerModule() {
        super(NAME);
        addSerializer(Container.class, new ContainerSerializer());
    }

    public static class ContainerSerializer extends JsonSerializer<Container> {
        @Override
        public void serialize(Container container, JsonGenerator jg, SerializerProvider serializers) throws IOException {
            if (container != null) {
                // start object and write description
                jg.writeStartObject();
                jg.writeStringField("description", container.description);

                // only write Element1 if one of its members exist
                Element1 element1 = container.element1;
                if (element1 != null) {
                    if (!Strings.isNullOrEmpty(element1.f11)
                            && !Strings.isNullOrEmpty(element1.f12)) {
                        jg.writeFieldName("element1");
                        jg.writeObject(element1);
                    }
                }

                // only write Element2 if one of its members exist
                Element2 element2 = container.element2;
                if (element2 != null) {
                    if (!Strings.isNullOrEmpty(element2.f21)
                            && !Strings.isNullOrEmpty(element2.f22)) {
                        jg.writeFieldName("element2");
                        jg.writeObject(element2);
                    }
                }

                // close the Container object
                jg.writeEndObject();
            }
        }
    }
}

注册自定义序列化程序

可以使用@JsonDeserializeObjectMapper或类上全局注册序列化程序。

ObjectMapper注册

1
2
ObjectMapper om = new ObjectMapper()
        .registerModule(new ContainerModule());

班级注册

1
2
3
4
5
6
@JsonSerialize(using = ContainerModule.ContainerSerializer.class)
public class Container {
    String description;
    Element1 element1;
    Element2 element2;
}

这应该产生以下结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// Full container
{
 "description" :"an awesome description",
 "element1" : {
   "f11" :"f11 value",
   "f12" :"f12 value"
  },
 "element2" : {
   "f21" :"f21 value",
   "f22" :"f22 value"
  }
}

// Null Element1 properties
{
 "description" :"an awesome description",
 "element2" : {
   "f21" :"f21 value",
   "f22" :"f22 value"
  }
}

// Null Element2 properties
{
 "description" :"an awesome description",
 "element1" : {
   "f11" :"f11 value",
   "f12" :"f12 value"
  }
}

// Null Element1 and 2 properties
{
 "description" :"an awesome description"
}


如果你使用注释,这应该工作正常:

1
2
3
4
5
6
7
public class Container{
    String description;
    @JsonIgnore
    Element1 element1;
    @JsonIgnore
    Element2 element2;
}

所以杰克逊忽略了@JsonIgnore注释的这两个