Getting error to unmarshalling object from xml using resttemplate - spring

I am using resttemplate of spring to invoke rest api getting error to unmarshall xml to object my code is:-
String uri = "http://devd.webservice.com/devpl/api/1.0/credential?apiKey=" + apiKey + "&signature=" + signature + "&timeStamp=" + timeStamp;
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("accountName", accountName);
requestHeaders.set("containerName", containerName);
requestHeaders.set("folderPath", folderPath);
requestHeaders.set("Content-Type","application/xml");
requestHeaders.set("Accept","application/xml");
RestTemplate template = getRestTemplate();
HttpEntity<String> requestEntity = new HttpEntity<String>(requestHeaders);
Credential result =(Credential)template.postForObject(uri,requestEntity,Credential.class);
Object classs bean on which i consume object:-
package com.simplidrivechn.netmagicsolutions.bean;
import com.thoughtworks.xstream.annotations.*;
#XStreamAlias("credential")
public class Credential
{
private String DestinationUrl;
private String AuthToken;
private String StorageUrl;
public String getAuthToken() {
return AuthToken;
}
public void setAuthToken(String AuthToken) {
this.AuthToken = AuthToken;
}
public String getDestinationUrl() {
return DestinationUrl;
}
public void setDestinationUrl(String DestinationUrl) {
this.DestinationUrl = DestinationUrl;
}
public String getStorageUrl() {
return StorageUrl;
}
public void setStorageUrl(String StorageUrl) {
this.StorageUrl = StorageUrl;
}
}
My spring configuration file:-
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean id="messageConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="xstreamMarshaller" />
<property name="unmarshaller" ref="xstreamMarshaller" />
</bean>
</list>
</property>
</bean>
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="aliases">
<props>
<prop key="credential">com.simplidrivechn.netmagicsolutions.bean.Credential</prop>
</props>
</property>
</bean>
</beans>
I am getting error:-
Exception in thread "main" org.springframework.http.converter.HttpMessageNotReadableException: Could not read [class com.simplidrivechn.netmagicsolutions.bean.Credential]; nested exception is org.springframework.oxm.UnmarshallingFailureException: XStream unmarshalling exception; nested exception is com.thoughtworks.xstream.mapper.CannotResolveClassException: Credential : Credential
please help me to resolve this error

Looking at your exception, it looks like that XStreamMarshaller's aliases are not set correctly in your spring context. You must make sure that your keys are 'aliases', i.e. root element in your case. Is 'credential' the root element of the xml response you are trying to deserialize? Note that aliases are case sensitive. Following code works for me. Note aliases.put("person", Person.class);My xml response has root element 'person'. If I change this key to lets say 'Person' like aliases.put("Person", Person.class); I exactly get the exception like you.
XStreamMarshaller marshaller = new XStreamMarshaller();
Map<String, Class> aliases = new HashMap<String, Class>();
aliases.put("person", Person.class);
marshaller.setAliases(aliases);
MarshallingHttpMessageConverter converter = new MarshallingHttpMessageConverter(
marshaller, marshaller);
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(converter);
template.setMessageConverters(converters);
HttpEntity request = new HttpEntity(null, headers);
ResponseEntity<Person> response = template.exchange(url,
HttpMethod.GET, request, Person.class);

Another way to define aliases is autoscan.
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="autodetectAnnotations" value="true"/>
<property name="annotatedClasses">
<array>
<value>com.simplidrivechn.netmagicsolutions.bean.Credential</value>
</array>
</property>
</bean>

Related

AJAX get returns 404 in Spring

help me
index.jsp
$("#btn-submit").click(function () {
var username=document.getElementById("username");
var password=document.getElementById("password");
$.ajax({
url:"login",
contentType: 'application/json;charset=utf-8',
dataType: 'text',
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
data: {
username:username.value,
password:password.value
},
type: 'get',
success: function (response) {
if (response=="1") {
alert(response);
}
else alert(response);
},
error: function (x, e) {
console.log(e)
}
});
});
LoginController.java
#RequestMapping("/login")
#Controller
public class LoginController {
#Autowired
private UserService userService;
#RequestMapping(value = { "/login" }, method = RequestMethod.GET)
#ResponseBody
public int checkValid(#RequestParam("username") String username,#RequestParam("password") String password, HttpServletRequest request, HttpServletResponse response, Locale locale, Model model){
try {
if (userService.findByUserName(username).equals(hashPass(password))){
return 1;
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return 0;
}
return 0;
}
public String hashPass(String pass) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hashInBytes = md.digest(pass.getBytes(StandardCharsets.UTF_8));
// bytes to hex
StringBuilder sb = new StringBuilder();
for (byte b : hashInBytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
}
spring-config-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
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-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
/WEB-INF/pages/
.jsp
/resources/jdbc.properties
<!-- Enable Annotation based Declarative Transaction Management -->
<tx:annotation-driven proxy-target-class="true"
transaction-manager="transactionManager" />
<!-- Creating TransactionManager Bean, since JDBC we are creating of type
DataSourceTransactionManager -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="postsDAO" class="com.blog.dao.impl.PostsDAO">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="postsService" class="com.blog.service.impl.PostsService">
<property name="postsDAO" ref="postsDAO"/>
</bean>
<bean id="userDAO" class="com.blog.dao.impl.UserDAO">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="userService" class="com.blog.service.impl.UserService">
<property name="userDAO" ref="userDAO"/>
</bean>
I use tomcat 9
Error:Failed to load resource: the server responded http://localhost:8080/Blog_war_exploded/login?username=root&password=root with a status of 404 ()
Look at your error: You are accessing http://localhost:8080/Blog_war_exploded/login but you actually want to access http://localhost:8080/login.
The reason is that you specified your URL as login instead of /login, so it is relative to the current "directory" and not to the root.
Changing the code to use /login should fix it:
$.ajax({
url: "/login",
...
})
On a side note, it's not a good idea to this via GET requests - among other things, the password will be stored in the server log in clear text. You should use a POST request instead.
Update:
Also, it seems you are use two request mappings for /login on top of each other, so you'll end up with /login/login. Check out how to use #RequestMapping properly.
Try changing the second (method-level) one to #RequestMapping(value = { "/" }, method = RequestMethod.GET) or just #RequestMapping("/").
I think the issue is related to your RequestMapping definition on both controller level and method level.
the first login at the controller level, means if you want to access any services in this controller, your requests have to start with "/login"
#RequestMapping("/login")
#Controller
public class LoginController {
and the second login at the method level, means you want to call the /login service under /login.
#RequestMapping(value = { "/login" }, method = RequestMethod.GET)
#ResponseBody
public int checkValid(#RequestParam("username") String username,#RequestParam("password") String password, HttpServletRequest request, HttpServletResponse response, Locale locale, Model model){
So the valid URL to call the /login service under /login controller is: /login/login
and because of this, your url /login was not found
you can either remove the first /login at the controller level, or use the /login/login from your ajax request...

Camel & CXF & REST: ERROR No message body writer has been found for class java.util.ArrayList, ContentType: application/json

In my Spring configuration file:
<bean id="jacksonJsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
<bean id="restJacksonProviderList" class="java.util.ArrayList">
<constructor-arg>
<list>
<ref bean="jacksonJsonProvider"/>
</list>
</constructor-arg>
</bean>
//......
<route id="RestMyRoute">
<from id="RestRequest" uri="cxfrs:/rest/MyService?resourceClasses=com.myself.services.MyService&bindingStyle=SimpleConsumer&providers=#restJacksonProviderList" />
<to uri="direct:doRoute" />
</route>
The Service interface:
#GET
#Path("/my/something/{id}")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#WebMethod
#WebResult(name = "getSomethingResponse")
public List<MySomething> getSomething(
#PathParam("id") #WebParam(name = "id") String id);
The code above works! I can send the get request to the URl and I get a JSON response.
Now, I do a small change: Instead of defining the web service's URL (and the route) by XML configuration, I define them by Java code:
public class MyRoute extends RouteBuilder {
private String uriRest = "cxfrs:/rest/MyService?resourceClasses=com.myself.services.MyService&bindingStyle=SimpleConsumer&providers=#restJacksonProviderList";
#Override
public void configure() throws Exception {
from(uriRest).
to("log:input").
to("direct:doRoute").
to("log:output");
}
}
When I hit the web service URL, I am getting 500 Internal Server Error and in the logs (Tomcat) I see JAXRSUtils ERROR No message body writer has been found for class java.util.ArrayList, ContentType: application/json
Actually the debugger tells me that defining the URI by Java code is recognized, since I do hit the code inside the route.
I saw this error in many answers here, basically they say to add a Json provider and assign it to the CXF endpoint.
Seems to me like it is what I have done. But it does not work.
Any idea what I am doing wrong here?
As peeskillet said, it's because there isn't a list of providers registered under the name restJacksonProviderList. You can get the JndiContext like this and bind a list to it in the configure method of your routebuilder:
JndiContext registry = (JndiRegistry) context.getRegistry();
registry.bind("restJacksonProviderList", Arrays.asList(new JacksonJsonProvider()));
Edit after comments:
Change & for & in your cxfrs uri definition, & is only needed in xml.

Spring Controller sending image to client results in 406

I'm trying to send an image to the front end upon request, it works if i put it in the request body as part JSON, but i want to use image/png, makes more sense, but i get a 406 when i try that.
Controller:
#RequestMapping(value = RESTPaths.EQUIPMENT_FILE_GET_IMAGE + "/{equipmentId}", method = RequestMethod.GET,
produces = MediaType.IMAGE_PNG_VALUE)
public #ResponseBody byte[] insertDataFile(#PathVariable("equipmentId") final Long equipmentId)
throws InternalServerError {
return equipmentFileService.getImage(equipmentId);
}
Test (client):
mockMvc.perform(
get(RESTPaths.EQUIPMENT_FILE_CONTROLLER + RESTPaths.EQUIPMENT_FILE_GET_IMAGE + "/" + equipment.getId())
.with(httpBasic("user", "password")).accept(MediaType.IMAGE_PNG)
.contentType(TestUtil.APPLICATION_JSON_UTF8)).andDo(MockMvcResultHandlers.print()).andExpect(status().isOk());
}
What am i missing?
Try adding the mvc annotation in servlet-context.xml file which registers a ByteArrayHttpMessageConverter
<mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>image/jpeg</value> <value>image/png</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
Solved:
#RequestMapping(value = RESTPaths.EQUIPMENT_FILE_GET_IMAGE + "/{equipmentId}", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<byte[]> getImage(#PathVariable("equipmentId") final Long equipmentId)
throws InternalServerError {
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG);
return new ResponseEntity<byte[]>(equipmentFileService.getImage(equipmentId), headers, HttpStatus.OK);
}

How to pass request parameter to 'default-target-url'

I am setting 'cat=1' in the hidden field in login.jsp page and was expecting it to be available on the default-target-url. Entry in spring-security.xml is,
<form-login login-page="/login.html" default-target-url="/index.html"
authentication-failure-url="/loginfailed.html" />
and in the controller,
#RequestMapping(value="/index", method = RequestMethod.GET)
public String index(HttpServletRequest request) {
String cat = request.getParameter("cat");
if (cat != null && cat.equalsIgnoreCase("1")) {
return "add";
}
return "redirect:/index.jsp";
}
but cant get request parameter value (cat is null) so I believe it is because 'default-target-url' redirects the request (and does not forward it?). Is it the case?
If yes then is there any way I can pass parameter to the 'default-target-url'?
I have changed implementation approach a bit. Details give below,
spring-security.xml
<form-login login-page="/login.html" authentication-success-handler-ref="feedSuccessHandler"
authentication-failure-url="/loginfailed.html" />
<logout logout-success-url="/loggedout.html"/>
<beans:bean id="feedSuccessHandler"
class="main.java.com.sp.utilities.FeedSuccessHandler">
</beans:bean>
FeedSuccessHandler.java
public class FeedSuccessHandler implements AuthenticationSuccessHandler {
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
String cat = request.getParameter("cat");
if (cat != null && cat.equalsIgnoreCase("1")) {
response.sendRedirect(request.getContextPath()+"/add.html");
}else{
SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response);
if(savedRequest != null) {
response.sendRedirect(savedRequest.getRedirectUrl());
}else{
response.sendRedirect(request.getContextPath()+"/");
}
}
}
}
Application is working as desired also in future if I want to customize redirection based on roles, I can use same class.
It does redirect by defult, but there are a couple configuration options you can use to change this behavior. Both of them is defined on the AbstractAuthenticationTargetUrlRequestHandler which is the parent class of the two existing authentication success handler implementations (by default SavedRequestAwareAuthenticationSuccessHandler is used by the namespace configuration).
Set its targetUrlParameter property, so that it will check if the HTTP request has a parameter with that name. If so, it will redirect to the URL given in that request parameter.
Or set a custom redirectStrategy. The default implementation calls response.sendRedirect(), but you can change that as you like in your custom implementation.
You will have some difficulty though, because neither of these configuration points are exposed through the namespace configuration, so you will need to go a level deeper, and write the bean definitions manually.
The redirect is controlled by the Redirect Strategy definined in the redirectStrategy property of SimpleUrlAuthenticationSuccessHandler.
The Default for redirectStrategy is an instance of DefaultRedirectStrategy.
What you need to do is to implement you own redirectStrategy (implements RedirectStrategy).
And then configure it:
...
<bean id="usernamePasswordAuthenticationFilter">
...
<property name="authenticationSuccessHandler">
<bean
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="redirectStrategy">
<bean class="yourRedirectStrategy"/>
<property>
</bean>
</property>
</bean>

spring restTemplate POST parameters from complex object

I'm attempting to test our REST service using restTemplate using the postForObject(...) method.
unit test:
#Test
public void testPostOrder() {
String url = BASE_URL + "/orders/";
OrderDto orderDtoInput = new OrderDto();
orderDtoInput.setCustomerId(34);
UpdateReportDto updateReport = restTemplate.postForObject(url,
orderDtoInput, UpdateReportDto.class, new Object[] {});
}
the interesting piece of my configuration:
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<ref bean="formHttpMessageConverter" />
<ref bean="marshallingHttpMessageConverter" />
</list>
</property>
</bean>
<bean id="formHttpMessageConverter" class="org.springframework.http.converter.FormHttpMessageConverter">
</bean>
I understand that the FormHttpMessageConverter will convert to and from MultiValueMap and media type
application/x-www-form-urlencoded.
Is there any magic, or tools I can use or wire in to convert my Dto to a MultiValueMap ??? or do I need to cycle over the object properties and build my own MultiValueMap in my test?
my server is expecting to get POST parameters that look something like this:
id=11752&firstName=Joe&active=true&address1=1122&address2=2233&c
ellPhone=123-321-1234&childrensName1=bobby1&childrensName2=bobby2&childrensName3=bobby3&childrensName4=bobby4&city=someCity&
customHobbies=loves To Fly Planes&distributorId=407&email=doc#surgeon.com&fax=321-123-1234&fellowship=good fellows&fishing=false&golf=true&hunting=false&
insuranceCompany1=ins1&insuranceCompany2=ins2&insuranceCompany3=ins3&insuranceCompany4=ins4&lastName=Brownie&
mailMerge=true&medicalSchool=Granada U&officeDays=4&officeManager=manager&officeManagerPhone=456.654.4567&other=true&
paNurse=nurse 1&paNursePhone=345-543-3456&
phone=234-432-2345&
salesRepresentativeId=1935&specialty=meatball surgery&spouseName=Betty&state=AL&
surgeryDays=22&title=doc&version=2&zip=47474
promptValues[0].id=12&promptValues[0].miscPromptId=882&promptValues[0].value=meFirst&
promptValues[1].id=13&promptValues[1].miscPromptId=881&promptValues[1].value=youToo&residency=Jamaica General&
surgeonClinics[0].address1=newAddress&surgeonClinics[0].address2=newAddress2&surgeonClinics[0].city=clinic City&
surgeonClinics[0].email=email#clinic1.com&surgeonClinics[0].fax=123.456.7890&surgeonClinics[0].id=33273&
surgeonClinics[0].name=clinic name&surgeonClinics[0].phone=890-098-4567&
surgeonClinics[0].zip=34567&surgeonClinics[0].surgeryCenter1=MySurgeryCenter1&
surgeonClinics[0].surgeryCenter2=MySurgeryCenter2&
surgeonClinics[1].address1=newAddress11&surgeonClinics[1].address2=newAddress22&surgeonClinics[1].city=clinic2 City&
surgeonClinics[1].email=email#clinic2.com&surgeonClinics[1].fax=123.456.7890&surgeonClinics[1].id=33274&
surgeonClinics[1].name=clinic2 name&surgeonClinics[1].phone=890-098-4567&
surgeonClinics[1].zip=34567&
surgeonClinics[1].surgeryCenter1=MySurgeryCenter21&surgeonClinics[1].surgeryCenter2=MySurgeryCenter22&
Here's what I don't get: our RestServiceController method knows how to take this crazy parameter list and re-create our Dto object. We can successfully call it using curl. It seems that some reciprocal magic should exist on the client side to turn the Dto into the parameter list.
Here's the signature of the server side controller method:
// createOrder
#RequestMapping(method = { RequestMethod.POST, RequestMethod.PUT }, value = "/orders/")
#ResponseBody
public UpdateReportDto createOrder(OrderDto orderDto,
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) {
You can use RestTemplate with message converters. I have tested it and it works
RestTemplate restTemplate = new RestTemplate();
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(new MappingJackson2HttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
restTemplate.postForEntity(url, requestBodyObject, returnTypeClass);

Resources