Spring Boot向XML元素添加属性,但不在JSON响应中 上面的代码打印

我正在研究同时产生XML和JSON响应的API。我在响应中有一个元素,仅在XML响应中需要一个属性。另外,当值为null时,两种格式的元素都不应出现在响应中。

期望:
XML:

<name>john</name>
<status type="text">married</status>

JSON:

"name":"john"
"status":"married"

这是我的代码:

    /**
     * POJO with bunch of LOMBOK annotations to avoid boiler-plate code.
     */
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder(toBuilder = true)
    @Data
    public class User implements Customer,Serializable {

        private static final long serialVersionUID = 1L;

        private Status status;
        private String name;

        /**
         * Matrital status of the user.
         */
        @Builder
        @Value
        public static class Status {

            @JacksonXmlText
            private String maritalStatus;

            @JacksonXmlProperty(isAttribute = true)
            private String type = "text";
        }

    }

通过上述更改,我得到了正确的XML响应,但是JSON响应也返回了type=text

 "status" : {
    "maritalStatus" : "married","type" : "text"
  }

我尝试将@JsonValue添加到private String maritalStatus,这解决了JSON响应,但是由于没有将属性添加到元素中而破坏了XML响应。

有人可以帮忙吗?

yinxilin 回答:Spring Boot向XML元素添加属性,但不在JSON响应中 上面的代码打印

最简单的方法可能是为User.Status实现自定义序列化程序,并为不同类型的表示产生不同的输出。

class UserStatusJsonSerializer extends JsonSerializer<User.Status> {

    @Override
    public void serialize(User.Status value,JsonGenerator gen,SerializerProvider serializers) throws IOException {
        if (gen instanceof ToXmlGenerator) {
            ToXmlGenerator toXmlGenerator = (ToXmlGenerator) gen;
            serializeXml(value,toXmlGenerator);
        } else {
            gen.writeString(value.getMaritalStatus());
        }
    }

    private void serializeXml(User.Status value,ToXmlGenerator toXmlGenerator) throws IOException {
        toXmlGenerator.writeStartObject();

        toXmlGenerator.setNextIsAttribute(true);
        toXmlGenerator.writeFieldName("type");
        toXmlGenerator.writeString(value.getType());
        toXmlGenerator.setNextIsAttribute(false);
        toXmlGenerator.writeRaw(value.getMaritalStatus());

        toXmlGenerator.writeEndObject();
    }

    @Override
    public boolean isEmpty(SerializerProvider provider,User.Status value) {
        return value == null || value.getMaritalStatus() == null;
    }
}

从现在开始,您可以删除额外的XML批注并注册自定义序列化程序:

@AllArgsConstructor
@NoArgsConstructor
@Builder(toBuilder = true)
@Data
class User implements Serializable {

    private static final long serialVersionUID = 1L;

    private Status status;
    private String name;

    @Builder
    @Value
    @JsonSerialize(using = UserStatusJsonSerializer.class)
    public static class Status {
        private String maritalStatus;
        private String type = "text";
    }
}

简单的控制台应用用法如下所示:

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.Value;

import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;

public class JsonPathApp {

    public static void main(String[] args) throws Exception {
        List<User> users = Arrays.asList(
                createUser("John","married"),createUser("Tom",null));

        ObjectMapper jsonMapper = JsonMapper.builder()
                .enable(SerializationFeature.INDENT_OUTPUT)
                .serializationInclusion(JsonInclude.Include.NON_EMPTY)
                .build();
        for (User user : users) {
            System.out.println(jsonMapper.writeValueAsString(user));
            System.out.println();
        }

        XmlMapper xmlMapper = XmlMapper.builder()
                .enable(SerializationFeature.INDENT_OUTPUT)
                .serializationInclusion(JsonInclude.Include.NON_EMPTY)
                .build();
        for (User user : users) {
            System.out.println(xmlMapper.writeValueAsString(user));
            System.out.println();
        }
    }

    private static User createUser(String name,String maritalStatus) {
        return User.builder()
                .name(name)
                .status(User.Status.builder()
                        .maritalStatus(maritalStatus)
                        .build())
                .build();
    }
}

上面的代码打印

John的JSON:

{
  "status" : "married","name" : "John"
}

Tom的JSON:

{
  "name" : "Tom"
}

John的XML:

<User>
  <status type="text">married</status>
  <name>John</name>
</User>

Tom的XML

<User>
  <name>Tom</name>
</User>

注意,我们实现了UserStatusJsonSerializer#isEmpty方法,该方法定义了emptyStatus类的含义。现在,我们需要在您的JsonInclude.Include.NON_EMPTY应用程序中启用Spring Boot功能。将以下密钥添加到您的应用程序配置文件中:

spring.jackson.default-property-inclusion=non_empty

如果您不想全局启用包含,则只能使用@JsonInclude注释为一个属性启用它。

@JsonInclude(JsonInclude.Include.NON_EMPTY)
private Status status;

另请参阅:

,

一种以XML方式编组对象,而以JSON(不同字段等)另一种方式编组对象的解决方案是使用“ mixins”。 一种技巧是您必须手动注册mixin,这没有魔术。见下文。

Mixin界面:

public interface UserStatusXmlMixin {

    @JsonValue(false)
    @JacksonXmlText
    String getStatus();

    @JacksonXmlProperty(isAttribute = true)
    String getType();
}

实施:

@Value
public class UserStatus implements UserStatusXmlMixin {

    private String status;

    @JsonValue
    @Override
    public String getStatus() {
        return status;
    }

    @Override
    public String getType() {
        return "text";
    }

    /**
     * Returns an unmodifiable UserStatus when status is available,* otherwise return null. This will help to remove this object from the responses.
     */
    public static UserStatus of(final String status) {
        return Optional.ofNullable(status)
                       .map(UserStatus::new)
                       .orElse(null);
    }

}

我还必须手动注册“ mixin”。

@Configuration
public class AppJacksonModule extends SimpleModule {

    private static final long serialVersionUID = -1;

    private final Map<Class,Class> mixinByTarget;

    /**
     * Construct an AppJacksonModule.
     */
    public AppJacksonModule() {
        super("AppJacksonModule");
        this.mixinByTarget = Map.of(
                UserStatus.class,UserStatusXmlMixin.class
        );
    }

    @Override
    public void setupModule(final SetupContext context) {
        super.setupModule(context);
        final ObjectCodec contextOwner = context.getOwner();
        if (contextOwner instanceof XmlMapper) {
            mixinByTarget.forEach(context::setMixInAnnotations);
        }
    }

现在,如果输入参数为null,则我需要在任何地方使用UserStatus.of(..)创建UserStatus的地方,<status/>都不会出现在响应中。

本文链接:https://www.f2er.com/3106816.html

大家都在问