I'm trying to use MappingJacksonJsonView with Spring 3.0, without success. I don't know what I'm doing wrong, I think the problem is that I don't know how to tell to use the MappingJacksonJsonView to render a request. I tried to use the same name for view name and bean name of MappingJacksonView, but didn't work. I built a sample test application here: https://github.com/stivlo/restjson
In web.xml I've defined ContextLoaderListener and the mapping for dispatcherServlet.
In servlet-context.xml I've added
<mvc:annotation-driven/>
and
<bean name="jsonView"
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
In org.obliquid.restjson.web.ToDoList.java I set the logical view name as jsonView.
However, instead of using MappingJacksonJsonView, it looks for a JSP file, according to my JSP mapping.
message /restjson/WEB-INF/jsp/jsonView.jsp
description The requested resource (/restjson/WEB-INF/jsp/jsonView.jsp)
is not available.
What should I change to use MappingJacksonJsonView as a renderer?
UPDATE 1: In following tests I've found that if I add the following to my servlet-context.xml, JSON rendering works, but my other view, rendered as JSP (home) is not working anymore.
<!-- Resolve views based on string names -->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
UPDATE 2: I removed the BeanNameViewResolver and changed my ToDoList.java to return directly the Collection to be converted in JSON, instead of ModelAndView, with a #ResponseBody annotation, as follows:
#RequestMapping("/toDoList")
public #ResponseBody List<ToDoItem> test() {
List<ToDoItem> toDoList = new ArrayList<ToDoItem>();
toDoList.add(new ToDoItem(1, "First thing, first"));
toDoList.add(new ToDoItem(1, "After that, do the second task"));
return toDoList;
}
In this way it works. Even though the mapping is even more "magical". It makes me wonder, if a similar renderer exists for XML for instance, how does Spring know which renderer to pick?
Spring will use Accept header sent by the client to return most appropriate view. Here you will find my complete Spring MVC application that returns both JSON and XML.
As you can see, I only needed:
<mvc:annotation-driven />
I also used the same annotations: #RequestMapping to map request to a method and #ResponseBody to tell Spring that what I am returning from the controller is the actual response. It might however need some tweaking/formatting, and here Spring takes care of marshalling your object into most appropriate type like JSON.
You should do it this way:
In your xml file set the following: set
<mvc:annotation-driven />
After it you need to set Jackson serializer:
<bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jacksonMessageConverter"/>
</list>
</property>
</bean>
after it you can use it in your Controller:
#RequestMapping(value="/getObjects",method = RequestMethod.POST)
#ResponseBody
public List<MyObject> getCategories(){
List<MyObject> objects = daoService.gettAllObjects();
return objects;
}
Adding the following worked in my case
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="0" />
</bean>
So basically we should try to resolve any view as a bean first
you will need to see ContentNegotiatingViewResolver,and set defaultviews property to MappingJacksonJsonView, and #ResponseBody uses HttpMessageConverter to instead of ViewSolver,see the differences between them
http://ufasoli.blogspot.com/2013/08/viewresolver-vs-messageconverter-spring.html
Related
If my understanding is correct, you can add/remove params for saveEmployee() freely. For example, when you add "loc" as follows, saveEmployee() receives the "non-null object" when the event happens. And the same goes for queryParams.
#Controller
public class Employee {
#RequestMapping("/save")
public void saveEmployee(Locale loc,
#RequestParam Map<String, String> queryParams) {
// saving employee
}
}
How could this method receive non-null Locale object by just adding a param "loc" here?
I would like to know the logic behind this.
Spring does it for you by using LocaleResolver or LocaleContextResolver, for the current request locale, determined by the most specific locale resolver available, in effect, the configured LocaleResolver / LocaleContextResolver in an MVC environment.
21.3.3 Defining #RequestMapping handler methods
An #RequestMapping handler method can have a very flexible signatures. The supported method arguments and return values are described in the following section. Most arguments can be used in arbitrary order with the only exception of BindingResult arguments.
Supported method argument types
java.util.Locale for the current request locale, determined by the most specific locale resolver available, in effect, the configured LocaleResolver / LocaleContextResolver in an MVC environment.
Spring's DispatcherServlet which forwards request from client to your controller gives you that parameters. In order to do that, it search the object from ApplicationContext to which bean(Controller) belongs.
Spring looks at the method arguments, their types and annotations, then determines if it can provide an object of that type/annotation.
If it cannot, it'll throw an exception, otherwise it will call the method with the object it decided fits the type/annotation.
For the list of supported types/annotations, read the documentation:
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-arguments
As you can see, java.util.Locale is listed.
I think you need xml setting for your locale
Do you want to try the followning xml setting
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="en" />
</bean>
<mvc:interceptors>
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="language" />
</bean>
</mvc:interceptors>
I’m trying to understand a piece of Spring code that I need to adapt.
I have:
<bean id="…" class="…">
<property name="expr"
value="teams.contains(member.team) and not empty(member.projects)" />
</bean>
The corresponding class has a field
private Expression expr;
of type
org.apache.commons.jexl2.Expression
Now I am trying to find the appropriate Spring annotation to get rid of the XML file. But I cannot even understand how a simple String property can be injected as a jexl2.Expression object. How does this work?
A friend found the answer:
There was another XML file with this:
<bean id="bean_for_ExprConverter" class="package.of.custom.ExpressionConverter">
<constructor-arg ref="bean_for_JexlEngine"/>
</bean>
and also, in the project’s properties:
application.spring.converters = #{{\
#'bean_for_ExprConverter'\
}}
Thus, as long as the converter bean is defined, it should be enough to simply inject the expression string with the #Value annotation.
I am using #Cacheable for caching the result of a method at Service layer in Spring 3.2. following method code is used inside service Class:
#Cacheable("questions")
public List<ABClassObject> getSecutityQuestionsList(){
List<ABClassObject> list = new ArrayList<ABClassObject>();
----------------
list = ----[DAO call]
return list;
}
xml Configuration
<cache:annotation-driven />
<!-- Generic cache manager based on the JDK ConcurrentMap -->
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="questions" />
</set>
</property>
</bean>
Can't use EhCache because of using jdk 1.6.
By using the above code pattern i am unable to cache the List result.DAO is called all the time when i call the above method.
So, Suggest me whats wrong with the code.
Thanks in advance.
Some things you should check:
The class of getSecutityQuestionsList method is a spring bean, i.e, you don´t use a new operator anyway.
The method getSecutityQuestionsList is called from another bean
In your xml configuration put a context:component-scan base-package="xxxxx"
Put a break point inside your method. In the stack trace you should see some spring proxy stuff. When you call this method of your service, you should actually be calling a spring proxy.
Is there a way to use my SOAP web service(spring-ws, java) as a XML based RESTful service virtually?
I don't want to re-write whole my SOAP web service into RESTful from scratch in java, but I need to access it through iphone using REST, which they already have easy native support.
XMLGateway, Proxys..? or some extra java code? since my SOAP request and response is simply an XML file why can't I modify it to be used by a REST service?
Or without changing changing any logic and xml parsing in my application is that easy to add jax-rs annotations and create a rest request xml?
my config spring file is like this:
<bean id="webServicePluginDescriptor"
class="com.mysite.ws.configuration.MyWebservicePluginDescriptor" />
<bean id="payloadMapping"
class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
<property name="defaultEndpoint" ref="inferenceEndPoint" />
<property name="interceptors">
<list>
<ref local="validatingInterceptor" />
<ref local="payLoadInterceptor" />
</list>
</property>
</bean>
<bean id="payLoadInterceptor"
class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor" />
<bean id="validatingInterceptor"
class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
<property name="schema"
value="classpath:/wsdl/Request.xsd" />
<property name="validateRequest" value="true" />
<property name="validateResponse" value="false" />
</bean>
<bean id="PropertyResource" class="com.mysite.ws.im.PropertyResource">
<property name="resource"
value="/WEB-INF/client-specific/InferenceMachine.properties" />
</bean>
<bean id="inferenceEndPoint" class="com.mysite.ws.web.InferenceEndPoint">
<property name="messageWebService" ref="messageWebService" />
</bean>
<bean id="messageWebService" class="com.mysite.ws.service.MessageWebService"
scope="request">
<aop:scoped-proxy />
<property name="inferenceService" ref="inferenceService" />
</bean>
<bean id="Request" class="org.springframework.xml.xsd.SimpleXsdSchema">
<property name="xsd" value="classpath:/wsdl/Request.xsd" />
</bean>
<bean id="Response" class="org.springframework.xml.xsd.SimpleXsdSchema">
<property name="xsd" value="classpath:/wsdl/Response.xsd" />
</bean>
<bean id="Error" class="org.springframework.xml.xsd.SimpleXsdSchema">
<property name="xsd" value="classpath:/wsdl/Error.xsd" />
</bean>
<bean id="mwsid"
class="org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition">
<constructor-arg value="classpath:/wsdl/mtchwsdl.wsdl" />
</bean>
<bean id="inferenceService" class="com.mysite.ws.im.InferenceService"
scope="request">
<aop:scoped-proxy />
<property name="webServiceConfiguration" ref="wsPlayerConfiguration" />
<property name="properties">
<bean class="com.mysite.ws.im.PropertyResource">
<property name="resource"
value="/WEB-INF/client-specific/InferenceMachine.properties" />
</bean>
</property>
</bean>
<!-- ~~~~~~~ Application beans ~~~~~~~ -->
<bean id="wsPlayerConfiguration"
class="com.mysite.ws.configuration.WebServiceConfiguration"
scope="request">
<aop:scoped-proxy />
<property name="playerConfiguration" ref="playerConfiguration"></property>
<property name="configurationSetup" ref="configurationSetup"></property>
</bean>
and this is my endpoint class:
/**
* The EndPoint of the Web Service Application. This class gets the raw
* SOAP-body message from the Spring Payload Dispatcher and sends the message to
* the #see MessageService class. After it has gotten the response XML message
* it returns this back to the Spring Payload Dispatcher.
*/
public class InferenceEndPoint extends AbstractJDomPayloadEndpoint {
private MessageWebService messageWebService;
public InferenceEndPoint() {
}
#Override
protected Element invokeInternal(Element inferenceRequest) throws Exception {
Element ret = messageWebService.handleRequest(inferenceRequest);
return ret;
}
/**
* #param messageWebService
*/
public void setMessageWebService(MessageWebService messageWebService) {
this.messageWebService = messageWebService;
}
}
any ideas?
Spring-WS just adds some annotations to your beans and then you have Spring beans doing most of the heavy lifting. Presumably you have some classes annotated with #Endpoint, #PayloadRoot and the like. You should be able to re-use all of these in one of three ways.
If your Spring-WS endpoint classes are adapter pattern style (e.g. your Endpoint class is injected with a POJO service that does the real work), then you could do a similar adapter-style Spring MVC Controller (where REST exists in Spring 3.0).
If you have your annotations directly on your business logic class, then in theory, you should be able to just sprinkle on some more annotations (might get a little busy-looking).
If you have Spring-WS beans that are POX (and not SOAP), then you might be able to get away with some fancy URL mappings to give them more RESTful looking URLs
To migrate to the Spring 3 for REST support, add the appropriate #RequestMapping and another annotations to expose them as REST services to match specific URLs. While you're adding, you might as well remove the old #PayloadRoots and #Endpoint, but that may not be a big deal. Of course if you leave old Spring-WS annotations around, you'll still need the Spring-WS jars on your classpath, but as long as you are not using a Spring-WS servlet nor any other other beans in your Spring file - you should be okay (in theory...).
The biggest gotchas will be:
Don't forget to remove Spring-WS beans from your Spring file
DO remember to add the Spring MVC beans to your Spring file, and most importantly different Dispatcher servlet
REST security in Spring will be provided by Spring Security, not the same SOAP interceptors found in Spring-WS, so that will be a complete overhaul. The good news is that Spring Security is actually pretty easy to work with
Looking at your code, it's very difficult to tell what the best approach would be. REST and SOAP are really quite different ways of imagining how a web-based service interface could work: SOAP is all about method calls, and REST is all about resources, representations and links. To convert, you have to start from your underlying abstract API.
If your basic API is one of “I give you a document, you give me a response document” and there's no exposure of anything other than that, it's a very SOAP-oriented model. You can model that in REST through POSTing a document and getting a response, but it's not at all elegant. If you can instead think of your interface in terms of “here's an overall resource, with properties I can set, and certain operations I can do” then that maps to REST far more easily (the overall resource is represented as a document full of links to individual property resources and operations, and the individual properties can be GET and PUT – and possibly DELETEd – as necessary). Which style you've got… well, it looks a lot like you've got the first, but I'm only guessing because determining it for real would require looking at more of your code than you've shown.
There's nothing stopping you from send POST filled with XML to get results filled with XML back.
The simplest thing to do is somehow capture the SOAP requests going back and forth, and simply turn the request in to a template with the blanks being your parameters, and then using XPath on the resulting XML to pull your results out.
The only nit being you might need SOAPAction header in your POST, but likely not.
It's really no big deal. If you have dozens of methods, it's more of a pain. Also, if you're using any of the encryption parts of SOAP, then it's more of a pain. But if just a few, in the end it's just XML, and a bulk of that XML is boilerplate, so looked at that way, it's pretty straightforward.
Addenda:
If you have back end logic that you want to front with a more HTTP friendly service, then JAX-RS can to that quite easily, but it would require coding on the server end.
If you have an existing SOAP web service that you wish to use, then forget the whole SOAP part of the equation, and simply treat it as an HTTP web service that uses XML payloads. It's still SOAP, but you're not using any SOAP tooling on the client side. You're simply assembling XML payloads on the client requests (from templates would be easiest, IMHO), and consuming XML payloads as a result, and trading these over HTTP.
Depending on how many different methods on the existing web service you intend to call gives you an idea of the scope of the work involved. It's simple work (once you can view the payloads easily), but it's still work. If you only have a few methods, especially if the interface is stable and not changing, it's far easier to just work with the raw XML than learn and fight some new unfamiliar framework.
This is how I solved that problem, using Spring Boot + Spring Integration.
Having a WSDL of the SOAP WS, I used maven-jaxb2-plugin to have my Java POJO's generated at build time.
Optionally, you could create transformations to adapt those classes and attributes to what the REST client expected.
Using Spring Integration, I mapped every REST endpoint to a SOAP gateway like this:
#Bean
public IntegrationFlow myFlow(GenericTransformer reqTransformer, GenericTransformer resTransformer) {
return IntegrationFlows
.from(this.getRestGateway(POST, "/api/entity", MyRestResponse.class))
.transform(reqTransformer)
.handle(this.getSoapGateway("gwBean"))
.enrichHeaders(h -> h.header(HttpHeaders.STATUS_CODE, HttpStatus.OK))
.transform(resTransformer)
.logAndReply();
}
private HttpRequestHandlingMessagingGateway getRestGateway(HttpMethod method, String path, Class payloadType) {
HttpRequestHandlingMessagingGateway httpGateway = new HttpRequestHandlingMessagingGateway();
RequestMapping requestMapping = new RequestMapping();
requestMapping.setMethods(method);
requestMapping.setPathPatterns(path);
httpGateway.setRequestMapping(requestMapping);
httpGateway.setReplyTimeout(timeout);
httpGateway.setRequestPayloadTypeClass(payloadType);
httpGateway.setMessageConverters(asList(jsonConverter));
return httpGateway;
}
private MarshallingWebServiceOutboundGateway getSoapGateway(String nameBean) {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath(generatedClassesPackage);
SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory();
messageFactory.setSoapVersion(SoapVersion.SOAP_12);
messageFactory.afterPropertiesSet();
MarshallingWebServiceOutboundGateway webServiceGateway = new MarshallingWebServiceOutboundGateway(soapUri, marshaller);
webServiceGateway.setMessageFactory(messageFactory);
webServiceGateway.setBeanName(nombreBean);
return webServiceGateway;
}
It should be easy:
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<ref bean="myInterceptor" />
</list>
</property>
</bean>
but this way the interceptor isn't called.
By default, Spring will register a BeanNameUrlHandlerMapping, and a DefaultAnnotationHandlerMapping, without any explicit config required.
If you define your own HandlerMapping beans, then the default ones will not be registered, and you'll just get the explicitly declared ones.
So far, so good.
The problem comes when you add <mvc:annotation-driven/> to the mix. This also declares its own DefaultAnnotationHandlerMapping, which replaces the defaults. However, if you also declare your own one, then you end up with two. Since they are consulted in order of declaration, this usually means the one registered by <mvc:annotation-driven/> gets called first, and your own one gets ignored.
It would be better if the DefaultAnnotationHandlerMapping registered by <mvc:annotation-driven/> acted like the default one, i.e. if explicitly declared ones took precedence, but that's not the way they wrote it.
My current preference is to not use <mvc:annotation-driven/> at all, it's too confusing, and too unpredictable when mixed with other config options. It doesn't really do anything especially complex, it's not difficult or verbose to explicitly add the stuff that it does for you, and the end result is easier to follow.
Problem I faced: Spring MVC tag doesn't go well with custom definition of DefaultAnnotationHandlerMapping.
Why..? the reason is very well explained in the answers above.
Why i wanted to use DefaultAnnotationHandlerMapping? I want to define an interceptor for my every request. a Spring-Mobile interceptor to determine the USER AGENT..mobile or a browser?
Now Due to this clash of mvc-annotation and DefaultAnnotationHandlerMapping, I cant use DefaultAnnotationHandlerMapping anymore.
The problem comes down to how can i register my interceptors with tag.
The solution was simple...but hard to find. Posting it so it can be helpful to the other solution seekers..
Use tag and register the interceptor bean in your dispathcer-servlet.xml
example :
<mvc:interceptors>
<!-- This runs for all mappings -->
<bean class="main.com.XXX.MobileDeviceResolverHanlderInterceptor"/>
</mvc:interceptors>
The reason for this behaviour is that two beans of type org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping exist in the application context. Spring resolves the two, but asks only the first for interceptors. To fix this, the following init parameter should be set to the DispatcherServlet
<init-param>
<param-name>detectAllHandlerMappings</param-name>
<param-value>false</param-value>
</init-param>
This makes the dispatcher servlet use only the handlerMapping defined in the x-servlet.xml
It is beyond me why this is the default behaviour. I'm expecting an answer from the spring community.
In my case I can NOT get rid of <mvc:annotation-driven/> as I am using jackson for json support using annotation.
What I tried, moved my all interceptors <mvc:interceptors> in separate "xml" file (interceptor-config.xml) and imported it from my x-dispatcher-servlet.xml
<import resource="interceptor-config.xml"/>
It solve my issue and avoid default 'DefaultAnnotationHandlerMapping' beans my application context.
Rather than creating separate 'xml', you can copy/paste interceptor contents directly in 'x-dispatcher-servlet.xml'.
Following is my interceptor:
<mvc:interceptors>
<mvc:interceptor>
<!-- Intercepting specific URL -->
<mvc:mapping path="/abc/**" />
<bean id= "myInterceptor"
class="xx.xxx.xxx.MyInterceptor" />
</mvc:interceptor>
<mvc:interceptors>
In Spring MVC 3.0 you can use <mvc:interceptors> instead of manual defining the handler mapping.