Change date format in DTO JSON on returning through @ResponseBody
Asked Answered
M

1

2

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.

Meteoritics answered 13/3, 2019 at 12:23 Comment(3)
The format you get is ISO 8601. I don’t know how it came about, but it’s recommended to use it if you can. When you are on Java 8 or later, why are you using the long outdated and poorly designed Date class? You probably want Instant from java.time, the modern Java date and time API.Equal
@OleV.V. : Not an option. Both OrderData and OrderWsDTO are already defined in OTB code.Meteoritics
Orika is doing it's job successfully, I'd suggest you take a look at your JSON marshaller. Since you're using Spring, I'm going to take a guess that you're using Jackson. You will need to configure the format that you want. This link might help to get you started https://mcmap.net/q/218852/-spring-configure-responsebody-json-format/1018903 && baeldung.com/jackson-serialize-datesKnoll
R
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.

Reflection answered 16/3, 2019 at 14:33 Comment(3)
Did not work out. I copied the entire bean definition in my custom-web-spring.xml while replacing only the date adapter with my custom date adapter. My custom module is an addon so I have made the date adapter entry inside the : myaddon/acceleratoraddon/web/src/com/myproject/myaddon/adapters/IndDateAdapter.javaMeteoritics
Is your add-on loaded correctly? Also can you check which date adapter is the groovy returning : spring.getBean("jaxbContextFactory").getTypeAdapters();Reflection
Yes. I can hit the controllers declared in the addon. Also, I can see the custom date adapter getting copied in my original webservicescomons. Running the groovy and checking the bean value on debugging is giving the same value for OTB adapters not my custom one. If its not asking too much can you please try it in your codebase. You can check using any OTB, call that prints date, like: localhost:9002/customcommercewebservices/v2/basesite/orders/…Meteoritics

© 2022 - 2024 — McMap. All rights reserved.