I am trying to return a object from my controller which should be parsed to xml by spring.
But I used the #XmlNamedObjectGraph (from moxy eclipselink) annotation in my class to customize the returned object. So I have to set the property MarshallerProperties.OBJECT_GRAPH from the marshaller.
How can I access the marshaller, which is used by spring to parse my object, in my controller?
ie:
#RequestMapping(value = "/xml/", method = RequestMethod.GET, produces = "application/xml")
#ResponseBody
public ResponseEntity<Customer> getXml() {
Customer customer = _customerService.getById(12);
...
marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, "default");
...
return new ResponseEntity<>(customer, HttpStatus.OK);
}
Thanks for your help in advance.
It is like Sotirios Delimanolis said. You have to implement your own AbstractJaxb2HttpMessageConverter. But additional to that you have implementet an WebBindingInitializer and register it with:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="com.example.CommonWebBindingInitializer" />
</property>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter" />
<bean class="com.example.Jaxb2RootElementHttpMessageConverter" />
</list>
</property>
</bean>
<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
You'll need to implement your own AbstractJaxb2HttpMessageConverter class and override its createMarshaller method to provide a Marshaller with your own properties. Look at Jaxb2RootElementHttpMessageConverter for implementation hints.
Once you've implemented such a class, you'll need to register it as a HttpMessageConverter with your MVC stack. If you're doing your configuration through Java, look into WebMvcConfigurationSupport#configureMessageConverters(..). If you are doing it through XML, look into
<mvc:annotation-driven>
<mvc:message-converters>
<!-- bean goes here -->
</mvc:message-converters>
</mvc:annotation-driven>
If you need to customize the marshaller, create a marshalling view and configure the marshaller with the properties you need, this is an example of configuring a JAXB marshaller (see this answer):
<!-- XML view using a JAXB marshaller -->
<bean id="jaxbView" class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.company.AClass</value>
</list>
</property>
</bean>
</constructor-arg>
</bean>
<!-- Resolve views based on string names -->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
Related
I am new to java AOP. I am supposed to convert the following xml config to java annotation config in my spring boot application. May I know how exactly to convert this xml config to java annotation config:
I think none of the examples that I saw in stackoverflow match the pattern I am trying to convert.
<bean id="xyzRestTemplate"
class="org.springframework.web.client.RestTemplate">
<constructor-arg ref="xyzClientHttpRequestFactory" />
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="jaxbDataMarshaller" />
<property name="unmarshaller" ref="jaxbDataMarshaller" />
</bean>
</list>
</property>
<property name="interceptors">
<list>
<bean class="com.example.XYZHeaderRequestInterceptor" />
</list>
</property>
</bean>
<bean id="jaxbDataMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPaths">
<list>
<value>com.a.b.c.d.v2</value>
</list>
</property> </bean>
When people talk about converting from XML they don't mean necessarily doing the same thing exactly. What makes Spring Boot attractive isn't just that a configuration is a java class.
You should convert this to use RestTemplate https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-resttemplate.html
Then you just build the RestTemplate using the builder to have the JaxB marshaller and the interceptor you want.
Rest Template - XML Indentation
A nice testcase that passes with XML and passes with #Configuration classes will prove you got it right.
Consider this simple example -
public class Person
{
private String name;
private Date dateOfBirth;
// getters and setters here...
}
In order to initialize Person as a Spring bean, I can write the following.
<bean id = "Michael" class = "com.sampleDomainName.Person">
<property name = "name" value = "Michael" />
</bean>
But in the above bean definition, how can I set the dateOfBirth?
For eg. I want to set the dateOfBirth as
1998-05-07
Treat it like any other POJO (which is is)
<property name="dateOfBirth">
<bean class="java.util.Date" />
</property>
If you need to use an explicit value (such as 1975-04-10), then simply call one of the other constructors (although those which take year-month-day are deprecated). You could also use an explicit java.beans.PropertyEditor which Spring rolls with already (see section 6.4.2; note that you can write your own editors and register them for your own types). You need to register the CustomEditorConfigurer in your config:
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date"
value="org.springframework.beans.propertyeditors.CustomDateEditor"/>
</map>
</property>
</bean>
Then your data looks like:
<property name="dateOfBirth" value="1975-04-10" />
I might add that Date is not an appropriate data type to store a date-of-birth because Date is really an instant-in-time. You might like to look at Joda and use the LocalDate class.
One of the answers mentioned here is useful, but it needs additional information. The constructor arguments for the CustomDateEditor need to be supplied.
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date"> <ref local = "customDateEditor" />
</entry>
</map>
</property>
</bean>
<bean id = "customDateEditor" class="org.springframework.beans.propertyeditors.CustomDateEditor">
<constructor-arg>
<bean class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd" />
</bean>
</constructor-arg>
<constructor-arg value="true" />
</bean>
Now we can do
<property name="dateOfBirth" value="1998-05-07" />
Spring inject Date into bean property – CustomDateEditor
This paper give two suggestions:
Factory bean
CustomDateEditor
I suggest the "Factory Bean" because the CustomDateEditor is not supported in Spring 4.0+ and the Factory Bean is easy enough to use.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="dateFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd" />
</bean>
<bean id="customer" class="com.mkyong.common.Customer">
<property name="date">
<bean factory-bean="dateFormat" factory-method="parse">
<constructor-arg value="2010-01-31" />
</bean>
</property>
</bean>
</beans>
Use a CustomDateEditor. It's been in Spring since the early days.
Inside a web application, I'm using dozer mapper (5.3.2) to perform some object to object mappings.
DozerBeanMapper is instantiated using spring bean definition. Mapping file is provided as property in the spring context xml.
<bean id="idmToBoMPersonMapper" class="org.dozer.DozerBeanMapper" lazy-init="false" scope="singleton" >
<property name="mappingFiles" value="config/IiIdmToBoMPersonMapping.xml"/>
</bean>
Mapping is working, but according to logs, instance of DozerBeanMapper is created every time the code uses the mapper.
INFO DozerBeanMapper:166 - Initializing a new instance of dozer bean mapper.
This is concerns me, I'd expect the mapper to be created once and only once.
I have tried to explicitly use scope="singleton" in the spring bean configuration, but that is not helping either.
Any suggestions for me to try?
I would be better to use the Spring integration with Dozer instead, namely the DozerBeanMapperFactoryBean, see here the documentation for further details:
<bean class="org.dozer.spring.DozerBeanMapperFactoryBean">
<property name="mappingFiles"
value="classpath*:/*mapping.xml"/>
<property name="customConverters">
<list>
<bean class=
"org.dozer.converters.CustomConverter"/>
</list>
</property>
<property name="eventListeners">
<list>
<bean class="org.dozer.listeners.EventListener"/>
</list>
</property>
<property name="factories">
<map>
<entry key="id" value-ref="bean-factory-ref"/>
</map>
</property>
</bean>
I'm moving an existing spring (3.1.1) web mvc Controller (called LoginController) to using annotations, I had
<bean id="loginHandlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="licenseInterceptor" />
<ref bean="propertyInterceptor" />
<ref bean="localeChangeInterceptor" />
</list>
</property>
<property name="urlMap">
<map>
<!-- used to include references to my LoginController -->
<entry key="error" value-ref="error" />
</map>
</property>
<property name="order">
<value>1</value>
</property>
</bean>
I changed my LoginController to be annotated. Some other classes had also been annotated previously so it will use the existing...
<bean id="requestMappingHandlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="interceptors">
<list>
<ref bean="licenseInterceptor" />
<ref bean="loginInterceptor" />
<ref bean="propertyInterceptor" />
</list>
</property>
</bean>
LoginController cannot use the loginInterceptor that others use however as it's a pre-login Controller but a post-login Interceptor.
What I want to know, is there a way to tell Spring that this specific Controller should NOT be used with a specific (loginInterceptor) Interceptor? And perhaps if it (and only it) could also use localeChangeInterceptor.
What have I tried
(works in Spring 3.2) Adding <mvc:interceptors> and their namespace to config but they don't seem to allow multiple bean references and exclude-mapping is Spring 3.2, I'm 3.1.1
Doing the processing in LoginInterceptor, handler is not of type LoginController - I can do ((HandlerMethod)handler).getBean() instanceof LoginController and that works but it's not pretty or flexible.
using the spring mvcnamespace you could do the following:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/login"/>
<ref bean="loginInterceptor"/>
</mvc:interceptor>
<!-- .. further interceptors -->
</mvc:interceptors>
this allows to add paths that should not be intercepted by a specific interceptor.
add the mvc namespaces to your configuration root element..
xmlns:mvc="http://www.springframework.org/schema/mvc"
... and the schema ...
xsi:schemaLocation=" .....
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
...."
I've done this in the past by implementing it in the preHandle method in a HandlerInterceptorAdapter.
#Override
public final boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// inspect handler object to see if it's LoginController
}
Here is what it took to get this working in the LoginController. A little like the solution of #blank but with some other nonsence, I'd still like to have a spring (annotation or config) way of fixing this though
public final boolean preHandle(HttpServletRequest request)
{
if (handler instanceof HandlerMethod &&
((HandlerMethod)handler).getBean() instanceof LoginController)
{
return true;
}
...
}
I want to configure AnnotationMethodHandlerExceptionResolver by adding jackson message converter. The problem is that I have already configured message converters in <mvc:message-converters> by creating a bean, and I can't reference it in AnnotationMethodHandlerExceptionResolver neither use ref in <mvc:message-conferters>
<mvc:annotation-driven>
<mvc:message-converters register-defaults="false">
<bean id="mappingJackson2" class="pl.styall.scylla.json.config.CustomMappingJackson2">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="outboundExceptionAdapter"
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver">
<property name="messageConverters">
<list>
<ref bean="mappingJackson2" />
</list>
</property>
</bean>
I could define two beans one for <mvc:message-converters> and AnnotationMethodHandlerExceptionResolver, but it is probably not the best idea. Is there other way to do this?
This is not supported yet, but it is on the 3.2 backlog. So it might be supported in 3.2.
See Add support for <ref> in addition to <bean> for <mvc:message-converters> for the Spring feature request.