【问题标题】:Convert a json to an array of objects in spring integration在spring集成中将json转换为对象数组
【发布时间】:2014-12-03 03:44:40
【问题描述】:

我们从服务(http 出站网关)以 json 格式返回一个对象数组,我们需要将它序列化回一个对象数组/POJOS。首先,我们尝试通过将 XML 配置设置为

来简单地序列化没有任何数组列表的 POJO
<int:json-to-object-transformer input-channel="testJsonToObjectChannel"
            output-channel="testChannel" type="com.that.service.service.test.ApplicationTestDomain" />

并让转换器和 http 出站网关返回相同的对象。然而,在将其转换为“ApplicationTestDomain”POJO 数组后,我们得到了堆栈跟踪中提到的错误,其中特别提到了

"No converter found capable of converting from type java.util.ArrayList<?> to type com.that.service.service.test.ApplicationTestDomain"

我们还尝试了一个简单的字符串数组,它们也成功地序列化和反序列化,只有当我们尝试序列化和反序列化对象数组时才会出现问题。

关于需要做什么才能解决的任何想法

以下是返回数组列表的服务

@Service("applicationTestService")
public class ApplicationTestService {

    private static Logger logger = Logger.getLogger(ApplicationTestService.class);

    public ArrayList<ApplicationTestDomain> getTestThatData(Message<?> inMessage){
        ArrayList<ApplicationTestDomain> testData = new ArrayList<ApplicationTestDomain>();

        ApplicationTestDomain testDomain = new ApplicationTestDomain();
        testDomain.setId(1L);
        testDomain.setTotalPrice(100.00D);
        testDomain.setTotalTaxes(70.00D);
        testDomain.setTotalAll(70D);

        testData.add(testDomain);

        return testData;
    }

}

以下是接收数组列表的服务

@MessageEndpoint("applicationDataTransformer")
public class ApplicationTransformer {

    public ApplicationResponse transformData(ArrayList<ApplicationTestDomain> response) {
        return new ApplicationResponse();
    }
}

以下是xml配置

<int-http:outbound-gateway request-channel="applicationConfigurationRequest" 
                           reply-channel="testJsonToObjectChannel"
                           url="http://localhost:8080/testapplication/services/application/testService"
                           http-method="GET"
                           expected-response-type="java.lang.String"/>


<int:json-to-object-transformer input-channel="testJsonToObjectChannel"
        output-channel="testChannel" type="java.util.ArrayList" />

<int:transformer input-channel="testChannel"
    ref="applicationDataTransformer"
    method="transformData"
    output-channel="applicationConfigurationResponse"/>         

以下是异常堆栈跟踪

at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:52)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
    at java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.messaging.MessageHandlingException: org.springframework.expression.AccessException: Problem invoking method: public com.that.domain.service.hotelavailability.HotelAvailabilityResponse com.that.transformer.service.ApplicationTransformer.transformData(java.util.ArrayList)
    at org.springframework.integration.handler.MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:78)
    at org.springframework.integration.transformer.AbstractMessageProcessingTransformer.transform(AbstractMessageProcessingTransformer.java:64)
    at org.springframework.integration.transformer.MessageTransformingHandler.handleRequestMessage(MessageTransformingHandler.java:68)
    ... 83 more
Caused by: org.springframework.expression.AccessException: Problem invoking method: public com.that.domain.service.hotelavailability.HotelAvailabilityResponse com.that.transformer.service.ApplicationTransformer.transformData(java.util.ArrayList)
    at org.springframework.expression.spel.support.ReflectiveMethodExecutor.execute(ReflectiveMethodExecutor.java:67)
    at org.springframework.expression.spel.ast.MethodReference.getValueInternal(MethodReference.java:122)
    at org.springframework.expression.spel.ast.MethodReference.access$000(MethodReference.java:44)
    at org.springframework.expression.spel.ast.MethodReference$MethodValueRef.getValue(MethodReference.java:258)
    at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:84)
    at org.springframework.expression.spel.ast.SpelNodeImpl.getTypedValue(SpelNodeImpl.java:114)
    at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:111)
    at org.springframework.integration.util.AbstractExpressionEvaluator.evaluateExpression(AbstractExpressionEvaluator.java:159)
    at org.springframework.integration.util.MessagingMethodInvokerHelper.processInternal(MessagingMethodInvokerHelper.java:268)
    at org.springframework.integration.util.MessagingMethodInvokerHelper.process(MessagingMethodInvokerHelper.java:142)
    at org.springframework.integration.handler.MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:75)
    ... 85 more
Caused by: org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.util.ArrayList<?> to type java.util.ArrayList<com.that.service.service.test.ApplicationTestDomain> for value '[{id=1, totalPrice=100.0, totalTaxes=70.0, totalAll=70.0}]'; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type java.util.ArrayList<?> to type com.that.service.service.test.ApplicationTestDomain
    at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41)
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:174)
    at org.springframework.integration.util.BeanFactoryTypeConverter.convertValue(BeanFactoryTypeConverter.java:123)
    at org.springframework.expression.spel.support.ReflectionHelper.convertArguments(ReflectionHelper.java:240)
    at org.springframework.expression.spel.support.ReflectiveMethodExecutor.execute(ReflectiveMethodExecutor.java:57)
    ... 95 more
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type java.util.ArrayList<?> to type com.that.service.service.test.ApplicationTestDomain
    at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:291)
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:177)
    at org.springframework.core.convert.support.CollectionToCollectionConverter.convert(CollectionToCollectionConverter.java:85)
    at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:35)
    ... 99 more

问候, 米琳达

【问题讨论】:

    标签: java xml json arraylist spring-integration


    【解决方案1】:

    你在这里的问题是你只使用原始java.util.ArrayList,你最终只使用ArrayList&lt;LinkedHashMap&lt;String, Object&gt;&gt;,而不是ArrayList&lt;LinkedHashMap&lt;String, ApplicationTestDomain&gt;&gt;

    试试这个技巧:

    type="com.that.service.service.test.ApplicationTestDomain[]"
    

    我们无法为Class 提供通用规范。

    但是使用该数组技巧,当框架将 Message 应用于您的服务方法的参数时,应该会自动从 Array 转换为 Collection

    从另一边&lt;int-http:outbound-gateway&gt;提供expected-response-type-expression,可以返回ParameterizedTypeReference&lt;?&gt;

    这里有一个技巧可以让他知道你想要的类型:

    <int:header-enricher>
            <int:header name="expectedResponseType">
                <int-groovy:script>
                    <![CDATA[
                        new org.springframework.core.ParameterizedTypeReference<List<com.that.service.service.test.ApplicationTestDomain>>() {}
                    ]]>
                </int-groovy:script>       
            </int:header>
    </int:header-enricher>
    
    <int-http:outbound-gateway request-channel="applicationConfigurationRequest" 
                           reply-channel="testJsonToObjectChannel"
                           url="http://localhost:8080/testapplication/services/application/testService"
                           http-method="GET"
                           expected-response-type-expression="headers.expectedResponseType"/>
    

    当然,有了这个,你就允许RestTemplate 使用 Jackson 将响应转换为所需的值。从这里开始,没有更多理由使用&lt;int:json-to-object-transformer&gt;,因为您已经有了 POJO 列表。

    【讨论】:

    • 嗨,这绝对解决了我的问题。然而,在更广泛的方案中,是否有一种更简洁的方法可以在不使用 ParameterizedTypeReference 的情况下做到这一点?如果实现这一点的唯一方法是使用它而不是在单独的标头丰富器元素中使用 ParameterizedTypeReference,那么至少可以单独指定 ParameterizedTypeReference 并直接在“expected-response-type-expression”属性中引用它
    • 是的,您可以作为方法参考。像这样的东西:expected-response-type-expression="T (org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandlerTests).testParameterizedTypeReference()"。该方法的作用:return new ParameterizedTypeReference&lt;List&lt;String&gt;&gt;() {};:github.com/spring-projects/spring-integration/blob/master/… 及其HttpOutboundWithinChainTests
    • 嗨,您如何设置 json 到对象转换器的预期类型,因为我有一个需要转换为对象列表的 json 数组。您将如何定义 json-to-object 转换器元素
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-21
    • 2020-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多