1

我遇到了一个问题,我的 JSON 响应可以是对象或对象数组

具有单个值的 Foobar 示例:

{
    "foo": {"msg": "Hello World" }
}

带有数组的 Foobar 示例:

{
    "foo": [
           { "msg": "Hello World" },
           { "msg": "Goodbye World" }
         ]
}

我希望将单个值强制转换为任何数组,但到目前为止,我发现将所有单个值转换为数组的唯一方法。


ACCEPT_SINGLE_VALUE_AS_ARRAY

http://wiki.fasterxml.com/JacksonFeaturesDeserialization


我一直在寻找对单个属性执行相同操作的注释,但到目前为止谷歌还没有出现任何示例。

以前有没有人遇到过这个问题,我真的不想将所有内容重写为数组以使 RestTemplate 与错误的服务一起使用。

4

3 回答 3

7

我希望将单个值强制转换为任何数组,但到目前为止,我发现将所有单个值转换为数组的唯一方法

这根本不应该是这样。对于给定的 ObjectMapper,该ACCEPT_SINGLE_VALUE_AS_ARRAY属性开/关的,但其行为完全由 JSON 值映射到的目标属性控制。

  • 当 ACCEPT_SINGLE_VALUE_AS_ARRAY 打开时,将 JSON 值映射到 Java 集合属性不会导致错误。
  • 当 ACCEPT_SINGLE_VALUE_AS_ARRAY 打开时,将 JSON 值映射到 Java 基本属性(也)不会导致错误。

由以下代码说明:

class Foo {
    private String msg;

    // Constructor, setters, getters
}

class Holder {
    private List<Foo> foo;
    private Foo other;

    // Constructors, setters, getters
}

public class FooTest {

    @org.junit.Test
    public void testCollectionFromJSONValue() throws Exception {
        final InputStream stream = Thread.currentThread()
                .getContextClassLoader().getResourceAsStream("foo.json");

        final String json = IOUtils.toString(stream);

        final ObjectMapper mapper = new ObjectMapper();
        mapper.configure(
                DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY,
                true);
        final Holder holder = mapper.readValue(json, Holder.class);
        System.out.println(holder);
    }
}

它依赖于以下 JSON:

{
    "foo": {
        "msg": "Hello World"
    },
    "other": {
        "msg": "Goodbye"
    }
}

运行代码将显示“foo”属性成功反序列化为列表,而“other”属性被反序列化为(基本)Foo 类型。

于 2013-04-09T19:51:35.957 回答
1

我遇到了同样的问题,并且很难找到一种解决方案来以这种方式配置我的 RestTemplate。因为您并不总是想实例化和更改 objectMapper ...所以这是我的解决方案:

<bean id="myRestTemplate" class="org.springframework.web.client.RestTemplate">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper" ref="jacksonObjectMapper" />
            </bean>
        </list>
    </property>
</bean>
<bean id="jacksonObjectMapper" class="com.fasterxml.jackson.databind.ObjectMapper" />
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="jacksonObjectMapper" />
    <property name="targetMethod" value="configure" />
    <property name="arguments">
        <list>
            <value type="com.fasterxml.jackson.databind.DeserializationFeature">ACCEPT_SINGLE_VALUE_AS_ARRAY</value>
            <value>true</value>
        </list>
    </property>
</bean>

然后,您可以通过将其注入代码中来使用此预配置的 RestTemplate:

@Autowired
private RestTemplate myRestTemplate;
于 2015-06-01T08:52:40.127 回答
0

使用 RestTemplate 时解决此问题的最佳方法。

import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
ObjectMapper objectMapper = new ObjectMapper()
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, false);
MappingJackson2HttpMessageConverter jacksonMappingConverter 
              = new MappingJackson2HttpMessageConverter(objectMapper);
restTemplate.getMessageConverters().add(0, jacksonMappingConverter);

对于要解析的元素,使用可以是对象或数组的注释定义如下

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
public class ParentObject{
  @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
  @JsonProperty("InnerObject")
 private List<InnerObject> innerObject;

}

如果您不想向 restTemplate 添加新的映射器,请更改现有的映射器以支持用例

List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
        for (HttpMessageConverter<?> httpMessageConverter : messageConverters) {
            if (httpMessageConverter instanceof MappingJackson2HttpMessageConverter) {
                MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = (MappingJackson2HttpMessageConverter) httpMessageConverter;
                mappingJackson2HttpMessageConverter.getObjectMapper()
                        .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
            }
        } 
于 2019-10-12T00:21:18.320 回答