Change date format in DTO JSON on returning throug

2020-04-14 08:47发布

问题:

I simply want to change the date format in my DTO returned by @ResponseBody

My question is not this question as my output is a JSON List and I am printing it on Postman instead of using a view with JS and other UI features.

It's not this one as well because I am returning a JSON List, not just the Date object.

It is an extension of this one, but I don't think Orika mapper is the culprit.

I am getting the timestamp value of date on returning the List using @ResponseBody.

My custom code-

@RequestMapping(value = "/my/report", method = RequestMethod.POST)
@ResponseBody
public List<OrderWsDTO> createReport() {
    //stuff
    return Optional.ofNullable(orderDataList)
            .orElse(Collections.emptyList())
            .stream()
            .map(orderData -> getDataMapper().map(orderData, OrderWsDTO.class, fields))
            .collect(Collectors.toList());
}

The mapper is: map:162, ConfigurableMapper (ma.glasnost.orika.impl)

Same issue with getDataMapper().mapAsList(orderDataList, OrderWsDTO.class, fields):

@RequestMapping(value = "/my/report", method = RequestMethod.POST)
@ResponseBody
public List<OrderWsDTO> createReport() {
    //stuff
    return getDataMapper().mapAsList(orderDataList, OrderWsDTO.class, fields);
}

OrderWsDTO is a DTO with getters and setters and a date field that is java.util.Date.

In postman I can see the date format as :
"date": "1552476861991"

The same exact call which returns OrderWsDTO instead of List<OrderWsDTO> changes the date format. It is printing the date as 2019-03-13T12:10:05+0000 which is format : yyy-MM-dd'T'HH:mm:ss.SSXXX

@RequestMapping(value = "/my/report", method = RequestMethod.POST)
@ResponseBody
public OrderWsDTO createReport() {
    //stuff
    return getDataMapper().map(orderData, OrderWsDTO.class, fields);
}


Why is the date showing two different formats when printed in List<DTO> and DTO?

Also, where is it getting the format : yyy-MM-dd'T'HH:mm:ss.SSXXX?


Edit 1:

The date is getting formatted here: de.hybris.platform.webservicescommons.jaxb.adapters.DateAdapter#marshal()
Format : yyyy-MM-dd'T'HH:mm:ssZ

Now, how to override this class?


Edit 2:

I am not able to override the jaxbContextFactory which has the list of adapters to modify the date. The jaxbContextFactory looks like-

<alias name="defaultJaxbContextFactory" alias="jaxbContextFactory"/>
<bean id="defaultJaxbContextFactory" class="de.hybris.platform.webservicescommons.jaxb.MoxyJaxbContextFactoryImpl">
    <property name="wrapCollections" value="${webservicescommons.messageconverters.context.wrapCollections}" />
    <property name="analysisDepth" value="${webservicescommons.messageconverters.context.analysisDepth}" />
    <property name="typeAdapters" ref="jaxbTypeAdaptersList" />
    <property name="subclassRegistry" ref="subclassRegistry" />
    <property name="otherClasses" ref="jaxbContextClasses" />
    <property name="metadataSourceFactory" ref="metadataSourceFactory" />
    <property name="excludeClasses"  ref ="jaxbContextFactoryExcludeClasses"/>
</bean>

On overriding this bean in my custom code it is still picking the old values for typeAdapters. Interestingly, it is replacing other properties with my custom properties.

My custom overridden bean-

<alias name="defaultJaxbContextFactory" alias="jaxbContextFactory"/>
<bean id="defaultJaxbContextFactory" class="de.hybris.platform.webservicescommons.jaxb.MoxyJaxbContextFactoryImpl">
    <property name="wrapCollections" value="false" />
    <property name="analysisDepth" value="30" />
    <property name="typeAdapters" ref="mylist" />
    <property name="subclassRegistry" ref="subclassRegistry" />
    <property name="otherClasses" ref="jaxbContextClasses" />
    <property name="metadataSourceFactory" ref="metadataSourceFactory" />
    <property name="excludeClasses"  ref ="jaxbContextFactoryExcludeClasses"/>
</bean>

<util:list id="mylist">
    <value>com.myproject.mymodule.myadapter</value>
    <value>de.hybris.platform.webservicescommons.jaxb.adapters.VariableMapAdapter</value>
    <value>de.hybris.platform.webservicescommons.jaxb.adapters.XSSStringAdapter</value>
</util:list>

For typeAdapters it is always picking the values-

<property name="typeAdapters">
        <list>
            <value>de.hybris.platform.webservicescommons.jaxb.adapters.DateAdapter</value>
            <value>de.hybris.platform.webservicescommons.jaxb.adapters.StringMapAdapter</value>
            <value>de.hybris.platform.webservicescommons.jaxb.adapters.XSSStringAdapter</value>
        </list>
    </property>

Edit 3:

I tried overriding the bean in mycustomaddon-web-spring.xml as -

<bean id="customJaxbContextFactory" parent="jaxbContextFactory">
    <property name="metadataSourceFactory" ref="customMetadataSourceFactory" />
    <property name="typeAdapters">
        <list>
            <value>myproject.adapters.DateAdapter</value>
            <value>de.hybris.platform.webservicescommons.jaxb.adapters.StringMapAdapter</value>
            <value>de.hybris.platform.webservicescommons.jaxb.adapters.XSSStringAdapter</value>
        </list>
    </property>
</bean>

I have added the custom adapter class i.e. myproject.adapters.DateAdapter in acceleratoraddon/web. Did not work out though.

回答1:

The 'jaxbContextFactory' bean is first defined in the 'webservicescommons-spring.xml' which creates the bean in the application context. So when you override the bean in your custom extension using (customExtension)-spring.xml, it is just overriding the bean in the application context. More information about context loading in Hybris can be found here.

The typeAdapters property mentioned in your comments is defined in another bean which is defined in the 'jaxb-converters-spring.xml'

<bean id="customJaxbContextFactory" parent="jaxbContextFactory">
        <property name="metadataSourceFactory" ref="customMetadataSourceFactory" />
        <property name="typeAdapters">
            <list>
                <value>de.hybris.platform.webservicescommons.jaxb.adapters.DateAdapter</value>
                <value>de.hybris.platform.webservicescommons.jaxb.adapters.StringMapAdapter</value>
                <value>de.hybris.platform.webservicescommons.jaxb.adapters.XSSStringAdapter</value>
            </list>
        </property>
    </bean>

Since the beans defined in the jaxb-converters-spring-xml are loaded in the WebApplicationContext, you will need to override this bean using the (customExtension)-web-spring.xml where you can define the bean and corresponding class in the websrc of your custom extension.