Unable to move from controller to view in Spring MVC - spring

I am using Spring MVC framework for my project.
I am unable to get my code running from controller to view.
Sharing the important chunk of code here.....
Inside AdminController.java controller
System.out.println("controller returning");
return new ModelAndView("dataFrame_","frameData",dataString);
Inside dispatcher-servlet.xml
<bean name="/dataFrame.htm"
class="com.organization.dept.spec.proj.module.controller.DataFrameController" >
</bean>
<bean id="dataFrameViewResolver"
class="com.organization.dept.spec.proj.module.view.DataFrameViewResolver">
<property name="dataFrameView">
<bean class="com.organization.dept.spec.proj.module.view.DataFrameView" />
</property>
<property name="dataFramePrefix" value="dataFrame_"></property>
</bean>
inside DataFrameViewResolver.java
public class DataFrameViewResolver extends AbstractCachingViewResolver {
private String dataFramePrefix;
private View dataFrameView;
#Override
protected View loadView (String viewName, Locale locale) throws Exception {
View view = null;
if(viewName.startsWith(this.dataFramePrefix)){
view = dataFrameView;
}
return view;
}
and
public String getDataFramePrefix() {
return dataFramePrefix;
}
public void setDataFramePrefix(String dataFramePrefix) {
this.dataFramePrefix = dataFramePrefix;
}
public View getDataFrameView() {
return dataFrameView;
}
public void setDataFrameView(View dataFrameView) {
this.dataFrameView = dataFrameView;
}
}
inside DataFrameView.java ...
public class DataFrameView extends AbstractView {
#Override
protected void renderMergedOutputModel(Map map, HttpServletRequest request,HttpServletResponse response) throws Exception {
System.out.println("RenderMergeoutputModel"); //line 99
I was unable to get the above system.out.println i.e. was unable to execute my code till that line 99.
The localhost log files of tomcat revealed some exception java.lang.ClassNotFoundException: javax.servlet.jsp.jstl.core.Config
I put the jstl-1.2.jar in lib and this could just get me rid of exception however still was unable get sysout of DataFrameView of line 99.

Related

MockMvc tests always returns status code 200 for get requests

I I am very new to spring boot and only have been working with it for a couple of days, so I am also very confused about this project (which is not my own). I am supposed to write tests with MockMvc for the rest controller, however each test with MockMvc only returns the status code 200 although it should be a 404.
Here is one of the tests:
#WebMvcTest(ObjectController.class)
#SpringJUnitConfig(TestConfig.class)
public class MvcTest {
#Autowired
MockMvc mockMvc;
#Test
public void shouldReturn404() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/obj/123"))
.andExpect(MockMvcResultMatchers.status().is(HttpStatus.NOT_FOUND.value()));
}
}
This is my rest controller I would like to test.
#RestController
#RequestMapping("obj")
public class ObjectController {
#Autowired
MyClass myClass;
#GetMapping()
public List<MyObject> findAll() {
List<MyObject> objList;
objList = myClass.getObjects();
return objList;
}
#GetMapping("/{id}")
public MyObject findById(#PathVariable String id) {
for (MyObject obj : myClass.getObjects()) {
if (obj.getId().equals(id))
return obj;
}
return null;
}
}
Then there is this class:
public class MyClass {
private List<MyObject> objList = new ArrayList<MyObject>();
public MyObject addObject(MyObject obj) {
objList.add(obj);
return obj;
}
public void setObjects(List<MyObject> objList) {
this.objList = objList;
}
public synchronized List<MyObject> getObjects() {
return objList;
}
}
There is an xml file that belongs to the class looking like this which can be found in the resource folder:
<?xml version='1.0' encoding='ISO-8859-1'?>
<beans xmlns='http://www.springframework.org/schema/beans'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:context='http://www.springframework.org/schema/context'
xsi:schemaLocation='http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd'>
<bean id='MyClass' class='it.is.some.path.MyClass'>
<property name='objList'>
<list>
<ref bean='[R01] Object1' />
</list>
</property>
</bean>
</beans>
The referenced beans can be found in separate files under resources too, in a sub folder called 'objList' and look like this:
<?xml version='1.0' encoding='ISO-8859-1'?>
<beans xmlns='http://www.springframework.org/schema/beans'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:context='http://www.springframework.org/schema/context'
xsi:schemaLocation='http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd'>
<bean id='[R01] Object1' class='this.is.some.path.MyObject'>
<property name='id' value='123' />
</bean>
</beans>
The myclass.xml as well as the folder with all xmls of the objects are imported via #ImportResource in the Application class.
And then there is
public class MyObject {
public String id = RandomStringUtils.randomAlphanumeric(5);
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
am sorry for the lengthy explanation but I have been spending two days now trying to figure out how to get MockMvc running and I feel like I am completely stuck. I would be very, very grateful if anybody could help out.
I assume 200 is the correct response as you have a mapping for /obj/{id} where {id} is a placeholder for any path variable like 123 in /obj/123.
Even though your controller returns null from a code perspective, Spring won't map this automatically to a 404 not found if this is what you would expect.
So you can literally try it with every path variable, you'll always get HTTP 200 because there wasn't any exception and the DisptacherServlet could properly route the HTTP request to a controller mapping. HTTP 200 is the default response code if you don't specify anything.
If you want your controller endpoint to return 404 when your MyObject is null, you have to be more explicit about this, e.g.:
#GetMapping("/{id}")
public ResponseEntity<MyObject> findById(#PathVariable String id) {
for (MyObject obj : myClass.getObjects()) {
if (obj.getId().equals(id))
return ResponseEntity.ok(obj);
}
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
}

Spring-WS - return valid response on Exception

I have soap andpoint which should return response type A based on request type B. But during processing of request, i'm expecting errors (like unable to call downastream service) which throw cutom exception for example type ExpEx. And now i wat to do custom error mapping, because in case of errors I don't want to return type A but want to return type CFault (which is defined in wsd also).
Now question:
- is is possible to create custom eero handle which rturn CFault instead A
- or is it possible to make enpoint allow to return two types of response A and CFault (I think Object) ?
my enpoint:
public class FantasticEndpoint extend WebServiceEndpoint {
private static final String NAMESPACE = "http://www.fantastic.com/SOA/tmp/FantasticService/v_2_4";
#PayloadRoot(namespace = NAMESPACE, localPart = "handleBOperation")
#ResponsePayload
public A createConsumers(#RequestPayload B b{
//do some dangerous logic possility throw EXCEPTION
// if EXCEPTION return CFault or return A if normal processing
}
}
First of all, take a look on that: https://docs.spring.io/spring-ws/sites/2.0/reference/html/server.html#server-endpoint-exception-resolver
I am going to highlight some of that:
According to documentation, you can create your own exception class to indicate the SOAP Fault that should be returned whenever that exception is thrown. Just annotate class with #SoapFault annotation.
import org.springframework.ws.soap.server.endpoint.annotation.FaultCode;
import org.springframework.ws.soap.server.endpoint.annotation.SoapFault;
#SoapFault(faultCode = FaultCode.SERVER)
public class MyCustomException extends Exception {
public MyClientException(String message) {
super(message);
}
}
If this doesn't suit you, you can mess with SoapFaultAnnotationExceptionResolver (https://docs.spring.io/spring-ws/site/apidocs/org/springframework/ws/soap/server/endpoint/SoapFaultAnnotationExceptionResolver.html). This resolver lets you map exception classes to SOAP Fault:
<beans>
<bean id="exceptionResolver" class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver">
<property name="defaultFault" value="SERVER"/>
<property name="exceptionMappings">
<value>
org.springframework.oxm.ValidationFailureException=CLIENT,Invalid request
</value>
</property>
</bean>
You can use this to add SoapFaultDetail:
public class MySoapFaultDefinitionExceptionResolver extends SoapFaultMappingExceptionResolver {
private static final QName CODE = new QName("code");
private static final QName DESCRIPTION = new QName("description");
#Override
protected void customizeFault(Object endpoint, Exception ex, SoapFault fault) {
if (ex instanceof MyCustomException) {
SoapFaultDetail detail = fault.addFaultDetail();
detail.addFaultDetailElement(CODE).addText("SOMECODE");
detail.addFaultDetailElement(DESCRIPTION).addText(ex.getMessage());
}
}
I have once used EndpointInterceptor to mess with SOAPHeader. Perhaps you can use it to do the work with SOAPFault (https://docs.spring.io/spring-ws/site/apidocs/org/springframework/ws/server/EndpointInterceptor.html).
You can extract SOAPFault from MessageContext like this:
#Override
public boolean handleFault(MessageContext messageContext, Object o) throws Exception {
SaajSoapMessage soapResponse = (SaajSoapMessage) messageContext.getResponse();
SOAPMessage soapMessage = soapResponse.getSaajMessage();
SOAPBody body = soapMessage.getSOAPBody();
SOAPFault fault = body.getFault();
//do something with fault here
return true
}
You can read about SOAPFault interface here https://docs.spring.io/spring-ws/site/apidocs/org/springframework/ws/soap/SoapFault.html

camel with twitter simple example

I am novice in apache-camel and I started with simple apache camel-twitter example using spring. I am using 2.20 version for camel and 2.19 version for camel-twitter. Below is my router code,
public class TwitterRouter extends RouteBuilder {
public void configure() throws Exception {
System.out.println("Test");
String twitter = "twitter://streaming/filter?type=event&keywords="+ URLEncoder.encode("london", "utf8")+"&consumerKey=key&consumerSecret=secretkey&accessToken=accesstoken&accessTokenSecret=accesstokensecret";
from(twitter).process(new Processor() {
public void process(Exchange exchange) throws Exception {
Status status = exchange.getIn().getBody(Status.class);
ProducerTemplate template = exchange.getContext().createProducerTemplate();
User user = status.getUser();
String name = user.getName();
System.out.println("name "+name);
template.sendBody("twitter","name "+name);
String screenName = user.getScreenName();
String text = status.getText();
}
});
System.out.println("Test1");
}
And my spring context file as below,
<bean id="routeBuilder" class="com.xyz.route.TwitterRouter" />
<camelContext xmlns="http://camel.apache.org/schema/spring">
<routeBuilder ref="routeBuilder" />
</camelContext>
So below are my queries,
After running program only Test and Test1 messages are printed on console. But whatever inside process method is not printed on console. I tried with producttemplate also but its not printing. So can anybody please help.
Also I tried to search for simpe camel-twitter example but not found. Does anybody have such example.

HttpInvokerServiceExporter + HttpInvokerProxyFactoryBean - Could not access HTTP invoker remote service

I'm trying to use HttpInvokerServiceExporter + HttpInvokerProxyFactoryBean, but whatever I do I get an exception:
org.springframework.remoting.RemoteAccessException: Could not access HTTP invoker remote service at [http://localhost:9999/testcaseapp/testcaseservice]; nested exception is java.io.IOException: Did not receive successful HTTP response: status code = 404, status message = [Not Found]
For the simplicity, I've created a test case.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class RemoteTest {
private static final Logger logger = LoggerFactory.getLogger("TestsLogger");
static interface TestCaseService {
public Integer add(Integer arg1, Integer arg2);
}
static class TestCaseServiceImpl implements TestCaseService {
public Integer add(Integer arg1, Integer arg2) {
return (arg1 != null ? arg1.intValue() : 0) + (arg2 != null ? arg2.intValue() : 0);
}
}
#Configuration
static class Config {
#Bean
public HttpInvokerServiceExporter httpInvokerServiceExporter() {
HttpInvokerServiceExporter httpInvokerServiceExporter = new HttpInvokerServiceExporter();
httpInvokerServiceExporter.setService(new TestCaseServiceImpl());
httpInvokerServiceExporter.setServiceInterface(TestCaseService.class);
return httpInvokerServiceExporter;
}
#Bean
public HttpInvokerProxyFactoryBean httpInvokerProxyFactoryBean() {
HttpInvokerProxyFactoryBean httpInvokerProxyFactoryBean = new HttpInvokerProxyFactoryBean();
httpInvokerProxyFactoryBean.setServiceInterface(TestCaseService.class);
httpInvokerProxyFactoryBean.setServiceUrl("http://localhost:9999/testcaseapp/testcaseservice");
httpInvokerProxyFactoryBean.afterPropertiesSet();
return httpInvokerProxyFactoryBean;
}
}
#Autowired
private TestCaseService[] testCaseServices;
private static Server server;
#BeforeClass
public static void setUp() {
try {
server = new Server();
SelectChannelConnector connector = new SelectChannelConnector();
connector.setPort(9999);
server.addConnector(connector);
//
WebAppContext webAppContext = new WebAppContext();
webAppContext.setContextPath("/testcaseapp");
webAppContext.setWar("src/test/java/" + RemotingTest.class.getPackage().getName().replace('.', '/'));
server.setHandler(webAppContext);
//
server.start();
} catch (Exception ex) {
logger.info("Could not permorm the set up: {}", ex.toString());
}
}
#AfterClass
public static void destroy() {
try {
server.stop();
} catch (Exception e) {
}
}
#Test
public void addTest() {
for (TestCaseService testCaseService : testCaseServices) {
Integer sum = testCaseService.add(10, 5);
Assert.assertNotNull(sum);
Assert.assertEquals(15, sum.intValue());
}
}
}
I've also tried to create a TestCaseService bean
#Bean public TestCaseService testCaseService() ...
and provide it as a httpInvokerServiceExporter argument
#Bean public HttpInvokerServiceExporter httpInvokerServiceExporter(TestCaseService testCaseService)
...
httpInvokerServiceExporter.setService(testCaseService);
but the result is still the same.
What am I doing wrong? Thanks!
I think the problem is that the Servlet is not accesible.
SERVER SIDE
Make sure you have in your WEB-INF/web.xml (on the app that is exposing the methods -SERVER-) this code:
<web-app>
...
<servlet>
<servlet-name>remoting</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>remoting</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
...
</web-app>
Here, the remote methods are served under "services", that is, for calling the method, the URL should be:
http://localhost:8080/sample/services/list
And you have to define this Servlet as accesible, by creating a bean (in my case under WEB-INF/remoting-servlet.xml):
<bean name="/list" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="service" ref="myObjectQueryService" />
<property name="serviceInterface" value="com.kategor.myapp.sample.service.ObjectQueryService" />
</bean>
CLIENT SIDE
If your using Spring under the client (not as in your example), you must define a bean for accessing the remote resources, defining some beans (one for each public resource):
In this case, it would be:
<bean id="listService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl" value="http://localhost:8080/sample/services/list" />
<property name="serviceInterface" value="com.kategor.myapp.sample.service.ObjectQueryService" />
</bean>
In your example is right.
This way, calling the Service "listService", you would have all the methods available in the class com.kategor.myapp.sample.service.ObjectQueryService
#Controller
public class HomeController {
// This is the remote service definition
#Autowired
private ObjectQueryService<MyObject, Long> objectQueryService;
/* .... */
/**
* List all Objects retrieved through Web Service from a remote Server
*/
#RequestMapping(value = "listRemoteWS", method = RequestMethod.GET)
public String listRemoteWS(Locale locale, Model model) {
StringBuilder result = new StringBuilder();
try {
// The Remote Service is called
List objs = objectQueryService.findAll(0, 10);
result.append(objs.size() + " objs found");
for (MyObject o : objs) {
result.append("<br>* ").append(o.getId()).append(" = ").append(o.getName());
}
} catch (Exception e) {
result.append("No objs have been found");
e.printStackTrace();
}
model.addAttribute("result", result);
return "index";
}
}
So I think the problem comes from the URL: maybe the service is not visible or this is not the correct path to it.
For more information, check this links (the first is really useful):
https://github.com/JamesEarlDouglas/barebones-spring-mvc/tree/master/reference/spring-remoting
http://www.ibm.com/developerworks/web/library/wa-spring3webserv/index.html
For me the problem was tomcat picked up two versions of the same applications. This raised the above error on running the client from STS in debug mode.
So solution is to clean up all the expanded webapp folders in tomcat for the application. Then redeploy the application.

Custom property editors do not work for request parameters in Spring MVC?

I'm trying to create a multiaction web controller using Spring annotations. This controller will be responsible for adding and removing user profiles and preparing reference data for the jsp page.
#Controller
public class ManageProfilesController {
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(UserAccount.class,"account", new UserAccountPropertyEditor(userManager));
binder.registerCustomEditor(Profile.class, "profile", new ProfilePropertyEditor(profileManager));
logger.info("Editors registered");
}
#RequestMapping("remove")
public void up( #RequestParam("account") UserAccount account,
#RequestParam("profile") Profile profile) {
...
}
#RequestMapping("")
public ModelAndView defaultView(#RequestParam("account") UserAccount account) {
logger.info("Default view handling");
ModelAndView mav = new ModelAndView();
logger.info(account.getLogin());
mav.addObject("account", account);
mav.addObject("profiles", profileManager.getProfiles());
mav.setViewName(view);
return mav;
}
...
}
Here is the part of my webContext.xml file:
<context:component-scan base-package="ru.mirea.rea.webapp.controllers" />
<context:annotation-config/>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>
...
/home/users/manageProfiles=users.manageProfilesController
</value>
</property>
</bean>
<bean id="users.manageProfilesController" class="ru.mirea.rea.webapp.controllers.users.ManageProfilesController">
<property name="view" value="home\users\manageProfiles"/>
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
However, when i open the mapped url, i get exception:
java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [ru.mirea.rea.model.UserAccount]: no matching editors or conversion strategy found
I use spring 2.5.6 and plan to move to the Spring 3.0 in some not very distant future. However, according to this JIRA https://jira.springsource.org/browse/SPR-4182 it should be possible already in spring 2.5.1.
The debug shows that the InitBinder method is correctly called.
What am i doing wrong?
Update:
public class UserAccountPropertyEditor extends PropertyEditorSupport {
static Logger logger = Logger.getLogger(UserAccountPropertyEditor.class);
public UserAccountPropertyEditor(IUserDAO dbUserManager) {
this.dbUserManager = dbUserManager;
}
private IUserDAO dbUserManager;
public String getAsText() {
UserAccount obj = (UserAccount) getValue();
if (null==obj) {
return "";
} else {
return obj.getId().toString();
}
}
public void setAsText(final String value) {
try {
Long id = Long.parseLong(value);
UserAccount acct = dbUserManager.getUserAccountById(id);
if (null!=acct) {
super.setValue(acct);
} else {
logger.error("Binding error. Cannot find userAccount with id ["+value+"]");
throw new IllegalArgumentException("Binding error. Cannot find userAccount with id ["+value+"]");
}
} catch (NumberFormatException e) {
logger.error("Binding error. Invalid id: " + value);
throw new IllegalArgumentException("Binding error. Invalid id: " + value);
}
}
}
There are no errors logged from UserAccountPropertyEditor.
I don't think you want to be specifying the field argument to WebDataBinder.registerCustomEditor(). This intended to work alongside form-backing objects, and you're not using that.
Try the simpler 2-arg method instead, and it should work:
binder.registerCustomEditor(UserAccount.class, new UserAccountPropertyEditor(userManager));
binder.registerCustomEditor(Profile.class, new ProfilePropertyEditor(profileManager));

Resources