Jackson xml将属性值映射到属性

问题描述 投票:0回答:1

我正在与旧系统集成,需要将以下xml解析到我的对象中。我试图用杰克逊做这个,但我不能让映射工作。任何人都知道如何将以下xml映射到pojo?

@JacksonXmlRootElement(localName = "properties")
@Data
public class Example {
    private String token;
    private String affid;
    private String domain;
}

xml示例:

<properties>
    <entry key="token">rent</entry>
    <entry key="affid">true</entry>
    <entry key="domain">checking</entry>
</properties>

我试过添加

@JacksonXmlProperty(isAttribute = true, localName = "key")

对于属性,但这当然不起作用,我没有看到另一种方法让这个工作。有任何想法吗?

我正在使用这样的映射器...

ObjectMapper xmlMapper = new XmlMapper();
dto = xmlMapper.readValue(XML_STRING, Example .class);

我使用以下依赖项

compile('org.springframework.boot:spring-boot-starter-web')
runtime('org.springframework.boot:spring-boot-devtools')
compileOnly('org.projectlombok:lombok')
testCompile('org.springframework.boot:spring-boot-starter-test')
compile('org.apache.commons:commons-lang3:3.5')
compile('com.fasterxml.jackson.dataformat:jackson-dataformat-xml')
compile('com.squareup.okhttp3:okhttp:3.10.0')
java spring-boot jackson-dataformat-xml xmlmapper
1个回答
0
投票

我彻底浏览了杰克逊,似乎没有办法实现这一目标。但是,我会在这里分享我的解决方案,以防它对其他人有用。

package com.example.config;

import com.example.dto.Example;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

public class Converter extends AbstractHttpMessageConverter<Example> {
    private static final XPath XPATH_INSTANCE = XPathFactory.newInstance().newXPath();
    private static final StringHttpMessageConverter MESSAGE_CONVERTER = new StringHttpMessageConverter();

    @Override
    protected boolean supports(Class<?> aClass) {
        return aClass == Example.class;
    }

    @Override
    protected Example readInternal(Class<? extends LongFormDTO> aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
        String responseString = MESSAGE_CONVERTER.read(String.class, httpInputMessage);
        Reader xmlInput = new StringReader(responseString);
        InputSource inputSource = new InputSource(xmlInput);
        Example dto = new Example();
        Node xml;

        try {
            xml  = (Node) XPATH_INSTANCE.evaluate("/properties", inputSource, XPathConstants.NODE);
        } catch (XPathExpressionException e) {
            log.error("Unable to parse  response", e);
            return dto;
        }

        log.info("processing populate application response={}", responseString);

        dto.setToken(getString("token", xml));
        dto.setAffid(getInt("affid", xml, 36));
        dto.domain(getString("domain", xml));

        xmlInput.close();
        return dto;
    }

    private String getString(String propName, Node xml, String defaultValue) {
        String xpath = String.format("//entry[@key='%s']/text()", propName);
        try {
            String value = (String) XPATH_INSTANCE.evaluate(xpath, xml, XPathConstants.STRING);
            return StringUtils.isEmpty(value) ? defaultValue : value;
        } catch (XPathExpressionException e) {
            log.error("Received error retrieving property={} from xml", propName, e);
        }
        return defaultValue;
    }

    private String getString(String propName, Node xml) {
        return getString(propName, xml, null);
    }

    private int getInt(String propName, Node xml, int defaultValue) {
        String stringValue = getString(propName, xml);
        if (!StringUtils.isEmpty(stringValue)) {
            try {
                return Integer.parseInt(stringValue);
            } catch (NumberFormatException e) {
                log.error("Attempted to parse value={} as integer but received error", stringValue, e);
            }
        }
        return defaultValue;
    }

    private int getInt(String propName, Node xml) {
        return getInt(propName, xml,0);
    }

    private boolean getBoolean(String propName, Node xml) {
        String stringValue = getString(propName, xml );
        return Boolean.valueOf(stringValue);
    }

    @Override
    protected void writeInternal(Example dto, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {
        throw new UnsupportedOperationException("Responses of type=" + MediaType.TEXT_PLAIN_VALUE + " are not supported");
    }
}

我选择将其隐藏在消息转换器中,因此我不必再次查看它,但您可以在您认为合适的地方应用这些步骤。如果选择此路线,则需要配置休息模板才能使用此转换器。如果没有,重要的是将xml缓存到Node对象中,因为每次重新生成将非常昂贵。

package com.example.config;

import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.MediaType;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@Configuration
public class RestConfig { 
    @Bean
    @Primary
    public RestTemplate restTemplate() {
        return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
    }

    @Bean
    public RestTemplate restTemplateLe(RestTemplateBuilder builder) {
        List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
        ExampleConverter exampleConverter = new ExampleConverter();
        exampleConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.TEXT_PLAIN));
        messageConverters.add(exampleConverter);

        return builder.messageConverters(messageConverters)
                      .requestFactory(new OkHttp3ClientHttpRequestFactory())
                      .build();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.