<beans:bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter>
<beans:property name="messageConverters">
<beans:list>
<beans:bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
</beans:list>
</beans:property>
</beans:bean>
what is the exact meaning of the above code? can anybody explain this.?
AnnotationMethodHandlerAdapter is deprecated and is replace by RequestMappingHandlerAdapter
These classes (as your configuration) are used to extend the HTTP request/response processing.
The class MappingJacksonHttpMessageConverter is a Jackson Json Framework converter which supports Json to Java Bean and vise-a-versa conversion.
Using this configuration, you don't have to convert Json to Java or Java to json. You can accept Java pojo in your controller method and return Java pojo from controller method. Conversion is handled by spring using mentioned converter class.
This way you can use annotations provided by Jackson on your pojo to control the output
Related
What is the purpose of conversion-service and content-negotiation-manager in Spring? We have this in our Spring appContext but I am not sure about its purpose.
For content-negotiation-manager:
I have read here:
http://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-config-content-negotiation that the content-negotiation-manager acts like a 'resolver' for #RequestMapping - e.g. if my mapping URL is "/person/create" - it will be called when the client accesses /person/create.json and /person/create.html (given the configuration below).
I am also able to access /person/list.xml and it returns an xml result even if xml is not defined in the content-negotiation-manager since I have the Jackson in my classpath:
For file extensions in the request URI, the MVC Java config and the
MVC namespace, automatically register extensions such as .json, .xml,
.rss, and .atom if the corresponding dependencies such as Jackson,
JAXB2, or Rome are present on the classpath.
So, we defined the content-negotiation-manager since we support html, and it is not mapped by default. Is my understanding correct?
For conversion-service:
In our classes, we have an ObjectMapper.readValue(json, Obj.class) and #RestController returning an object in xml/json format depending on the request (it returns an xml format if you access /list.xml and returns json format when you access /list.json). But I've read that #RestController can work without the conversion-service. So I am not sure why it is supplied in the <mvc:annotation-driven>
<mvc:annotation-driven conversion-service="conversionService" content-negotiation-manager="contentNegotiationManager"/>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="html" value="text/html"/>
</map>
</property>
<property name="defaultContentType" value="application/json"/>
</bean>
Both the conversion service and the content negotation manager are always used by Spring MVC, regardless whether you define them or not. You can configure them according to your needs. That's the case here.
E.g. name="defaultContentType" value="application/json" means that if the client doesn't prefer a specific media type the server should send back JSON.
I'm trying to upgrade to Spring 4.1.5.
I have a custom Object mapper defined like so
<bean id="apiObjectMapper" class="my.company.ApiObjectMapper" />
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager">
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="apiObjectMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
The object mapper itself looks like this:
public class ApiObjectMapper extends ObjectMapper {
private static final long serialVersionUID = 1L;
public ApiObjectMapper() {
JaxbAnnotationModule module = new JaxbAnnotationModule();
module.setPriority(Priority.SECONDARY);
registerModule(module);
setSerializationInclusion(JsonInclude.Include.NON_NULL);
configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
}
}
The issue happens during content negotiation it seems
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorParameter" value="true" />
<property name="defaultContentType" value="text/xml" />
<property name="mediaTypes" >
<value>
json=application/json
xml=text/xml
</value>
</property>
</bean>
After upgrading, the object mapper is simply ignored. No Jaxb annotations are taken into account, NULLs appear.
Spring 4.0.9 works fine.
I tried Java Configuration with the same result.
Also tried configuring the new Jackson2ObjectMapperFactoryBean directly, but couldn't get the original behavior to happen either.
E.g.: Original output for an endpoint like "list.xml"
<result>
<typeB>
<itemA>...</itemA>
<itemB>...</itemB>
</typeB>
</result>
Now outputs (typeA is empty/null):
<result>
<typeA />
<typeB>
<itemA>...</itemA>
<itemB>...</itemB>
</typeB>
</result>
Any ideas?
I believe I found the culprit and fix for this issue.
When the content negotiation determines that the response should be serialized in JSON then org.springframework.http.converter.json.MappingJackson2HttpMessageConverter is used. However, if the response should be serialized in XML then org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter is used instead. Different message converter that will use a default object mapper if none is provided.
What I had to change was
public class ApiObjectMapper extends XmlMapper { // XmlMapper extends ObjectMapper
// same logic
}
and
<bean id="apiObjectMapper" class="my.company.ApiObjectMapper" />
<mvc:annotation-driven content-negotiation- manager="contentNegotiationManager">
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="apiObjectMapper"/>
</bean>
<!-- Added this bean configuration for XML serialization -->
<bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter">
<property name="objectMapper" ref="apiObjectMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
I have yet to find what changed in Spring Framework or Jackson to make this happen although my money is n the separation of Jackson XML handling into a different library (I'll update this answer once I do).
Hope it helps.
Leaving some more information for future reference.
Based on this Spring blog post, starting with Spring 4.1, Jackson XML is used to generate XML instead of Jaxb if the former is found on the classpath. That's the main reason for the output to change, because the library generating it changed.
Now after some trial and error, getting Jackson XML to generate the same output as Jaxb is quite the endeavour. Instead you could just remove all references to Jackson XML (not Jackson itself) and everything should work the same way it worked before.
I am trying to configure Spring : LocalValidatorFactoryBean to set my custom TraversableResolver
I do the following in my applicationContext.xml :
<bean id="customTraversableResolver" class="com.package.core.resolver.SimpleTraversableResolver" />
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="traversableResolver" ref="customTraversableResolver" />
</bean>
But at runtime, #Valid bean in controller are validated with default traversable resolver (from hibernate validator).
So, how to configure default bean validation configuration in spring ?
Have you tried adding validation.xml and adding the traversable resolver configuration in there? Btw, what do you want to achieve with your custom resolver?
While you’re using Spring MVC, you must register your validator in this way:
<mvc:annotation-driven validator="validator" />
If you want method-level validation, then define bean:
<!-- Enable method-level validation on annotated methods via JSR-303 -->
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"
p:validatorFactory-ref="validator" />
Then you don’t need validator.xml anymore.
Note: This works with Spring 3.2.x and Hibernate Validator 4.x.
I am working on a project and I need to set the following bean and property but I dont want to do it in XML.. I want to do it in JavaCofig style.. Can someone please show me how I would do this in javaconfig stlye
<!-- Spring Configuration needed to avoid URI using dots to be truncated -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="useDefaultSuffixPattern" value="false" />
</bean>
Something like this should work:
#Bean public DefaultAnnotationHandlerMapping defaultAnnotationHandlerMapping(){
DefaultAnnotationHandlerMapping bean = new DefaultAnnotationHandlerMapping();
bean.setUseDefaultSuffixPattern(false);
return bean;
}
You can see my sample spring MVC app using code config here https://github.com/robhinds/spring-code-configuration-webapp/blob/master/src/main/java/com/tmm/web/configuration/WebMvcConfiguration.java
I am implementing a REST service with xml as the payload and have the following configuration to use Jaxb2Marshaller to unmarshall my xml. Here is the configuration from my spring context file
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.my.examples.Product</value>
</list>
</property>
<property name="schema" value="classpath:schemadefinitions/product.xsd" />
</bean>
On my bean Product I have just this annotation as
#XmlRootElement(name="product")
public class ProductInfo {
The issue is when I make the REST request it unmarshalls xml to bean properly but doesn't perform any validation against the schema configured with the marshaller. Am I missing anything ?
I had to attach a validationeventhandler to the marshaller as jaxb2Mashaller.setValidationEventHandler(...) Once this is set the unmarshaller started to validate input xml.
With Java 8 and JaxB 2.2.4, I don't see any problems with the original setup! Defining the schema property in the applicationcontext.xml is ALL you need to do in order to get schema validation going.
If one creates Jaxb2Marshaller "manually", one needs to make sure to call the afterPropertiesSet method after setting the schema resource, since it loads the schema resource into memory.