JAX-WS xsi:type attributes missing - soap

I have a JAX-WS webservice that works just fine except that the return elements are missing necessary xsi:type attributes.
response:
<ns1:isUserValidResponse xmlns:ns1="http://www.openuri.org/">
<isUserValidResult>true</isUserValidResult>
</ns1:isUserValidResponse>
desired response:
<ns:isUserValidResponse xmlns:ns="http://www.openuri.org/">
<isUserValidResult xsi:type="xsd:boolean">true</isUserValidResult>
</ns:isUserValidResponse>
Is there anyway to force this behavior?

I resolved this issue by using #XmlAttribute with the name being "xsi:type" and the value being "xsd:boolean" as shown below. This feels extremely hacky to me but it works in the mean time.
#XmlAttribute(name="xsi:type")
private String xsiType = "xsd:boolean";

Related

How to validate RestTemplate response?

Spring supports annotation based validation at the controller level.
(1) Is it necessary to do such validations also at the RestTemplate level for responses from REST calls?
If the answer is Yes:
(2) Will there be support for that at the RestTemplate to validate responses from rest calls sometime in the future?
If the answer is No:
(3) why?
It is 2020 now and I still do not see the requested feature in place.
The #Valid is nice to automatically validate e.g. a posted RequestBody.
But for the validation of the body of a ResponseEntity fetched via RestTemplate, I do not see any fancy equivalent.
So the only option I know, is to do it on your own taken from here. Input is the class of your RequestEntitys body. input is the body itself.
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<Input>> violations = validator.validate(input);
if (!violations.isEmpty()) {
throw new ConstraintViolationException(violations);
}
So to answer your question:
Yes I would validate the response!
future (2020) has not brought the feature you and I miss
For the reason why this is missing, I also have no answer.
For me, the questions are quite big. :). As my understanding, you would like to ask the validation in REST service that Spring can support.
1. Is it necessary to do such validations also at the RestTemplate level for responses from REST calls?
Actually, it depends on your apps or your business. You can do at Controller or you can do in Service Level or even you can do your custom validation. For me, no one forces you to do anything.
However, as my experience, we should do the validation for sure. So my answer here is YES.
2. Will there be support for that at the RestTemplate to validate responses from rest calls sometime in the future?
I assume that you would like the detail of the validation?! Right?
Spring supports many things to do the validation. For the simple way, you can use PathVariable or RequestParameter.For example:
#GetMapping("/test/{name}")
private String test(#PathVariable(value = "name", required = true) String name){
//...
}
Spring will validate all requests, and respond with 400 Bad Request when the required parameter is missing or has a wrong type...
Spring also supports the JSR 303 Bean Validation: http://beanvalidation.org/1.0/spec/ For example in here:
public class MessageBean {
#NotNull
private String title;
#NotNull
private String message;
// getters/setters/etc
}
Or you would like to do the Custom User Response like:
#ExceptionHandler
#ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleException(MethodArgumentNotValidException exception) {
//....
return ErrorResponse.builder().message(errorMsg).build();
}
Some more details in here: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-validation
So, it depends on the business which requires us to do the validation at any level.
3. If the answer is No: (3) why?
No need to answer this. :)
Hope that helps

Optional in path param in REST api Spring MVC

I have requirement to pass a Optional parameter (count) to GET method. I tried below.
#RequestMapping(value = {"/findDetail","/findDetail/{no}"}, method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public int findAll(#PathVariable Optional<Integer> no) {
//find method takes Optional argument.
return ticketService.find(no);
}
I am expecting some value here but no always has null. Did I miss something here?
I just tried this out, and it worked fine for me? no.get() gives 4 with a GET to /findDetail/4
I'm running with Spring MVC 4.2.6 (via Spring Boot 1.3.5) if that makes any difference?
Do you see a change if you do #PathVariable("no") Optional<Integer> no instead? (I can't see why you would, but worth a shot?)
But you definitely are on the right 'path' - what you said should work fine as pointed at in Optional path segments in Spring MVC amongst other answers.

Why can't I get HAL support to work in grails 2.3.8?

I am following the directions in the docs, here:
http://grails.org/doc/2.3.8/guide/webServices.html#hypermedia
Why won't grails produce HAL-formatted output, as shown in the documentation?
I have a domain object which I have mapped with the #Resource annotation:
#Resource(uri='/documentCatalogs', formats = ['json', 'xml'], readOnly = true)
class DocumentCatalog {
String entityType
String actionCode
...
}
...and in my conf/spring/resources.groovy, I have configured the HAL JSON renderer beans:
import com.cscinfo.platform.api.formslibrary.DocumentCatalog
import grails.rest.render.hal.HalJsonCollectionRenderer
import grails.rest.render.hal.HalJsonRenderer
// Place your Spring DSL code here
beans = {
halDocumentCatalogRenderer(HalJsonRenderer, DocumentCatalog)
halDocumentCatalogCollectionRenderer(HalJsonCollectionRenderer, DocumentCatalog)
}
Using the debugger, I confirmed that the initialize() method on HalJsonRenderer is called and that it is constructed with the correct targetType.
I send a rest call using Postman:
http://localhost:8080/formslibrary/documentCatalogs/3
Accept application/hal+json
And I get back a response which is regular JSON and doesn't contain any links:
{
"class": "com.cscinfo.platform.api.formslibrary.DocumentCatalog",
"id": 3,
"actionCode": "WITH",
"entityType": "LLP",
...
}
What did I miss? Is there some plugin or configuration setting I have to enable for this behavior? Is there some additional mapping property somewhere that's not documented?
Figured it out! There are multiple aspects of the fix...
I had to add "hal" as one of the listed formats in the #Resource annotation:
#Resource(uri='/documentCatalogs', formats = ['json', 'xml', 'hal'])
Some hunting around in the debugger revealed that Grails will blithely ignore the Accept header, based on the UserAgent string that is sent from the client. (In my case, since I'm using Postman, it was the Google Chrome UA string.)
One workaround for the Accept header issue is to add ".hal" to the end of the URL:
http://localhost:8080/formslibrary/documentCatalogs/3.hal
This isn't a very good solution IMO, since the HAL URLs generated by the renderer don't end in ".hal" by default.
A better solution is to fix Grails' handling of the accept header by updating the config. In Config.groovy, you will see a line that says:
grails.mime.disable.accept.header.userAgents = ['Gecko', 'WebKit', 'Presto', 'Trident']
Change it to:
grails.mime.disable.accept.header.userAgents = ['None']
This forces Grails to honor the Accept header, regardless of the user agent.
Hope this helps somebody else who's hitting the same issue.
P.S. It's really helpful to put a breakpoint in the ResponseMimeTypesApi#getMimeTypesFormatAware(...) method.

Returning XML object through jax-rs

I have a JAX-RS web service which looks like so:
#Path("/status")
#Produces("application/xml")
#GET
public PrecisionStatus getPrecisionValue(){
PrecisionStatus status = ...
return status;
}
Initially, the result was:
<PrecisionStatus sensorID="TemperatureSensor5"><condition>OK</condition><fieldValue>60.0</fieldValue></PrecisionStatus>
It looks fine, but I want to declare the xsd file which describes this document. By using JAXB marshalling features, I was able to produce (in logger/console) the desired output:
<PrecisionStatus sensorID="TemperatureSensor5" xsi:noNamespaceSchemaLocation="http://mysite.com/myapp/xsd0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<condition>OK</condition>
<fieldValue>60.0</fieldValue>
</PrecisionStatus>
(this is confirmed by unmarshalling the object).
However, if i return this object return status;, the browser receives the former xml document, namely the one without the reference to xsd.
I am pretty sure that the object has the right form, but somewhat the reference to xsd is stripped in the final result. Any clue?
You could create a JAX-RS MessageBodyWriter to have access to the Marshaller in order to set the JAXB_NO_NAMESPACE_SCHEMA_LOCATION property. For a complete example see:
Formatted XML output in CXF?

Complex (non string) return type for Jersey REST method

I'm having trouble setting something up that I'm pretty sure /should/ be easy, so I thought I'd throw it to the crowd. I can't seem to find what I'm looking for elsewhere on the web or on SE.
I am simplifying my project of course, but basically I have a JAX-WS annontated Jersey resource class that looks something like this:
#Path("myresource")
public class MyResource {
#Autowired
MyComplexObjectDAO daoInstance;
#Path("findObject/{id}")
#GET
public MyComplexObject findObject( #PathParam(value="id") String id ) {
return daoInstance.findObject( id );
}
#Path("saveObject")
#PUT
public MyComplexObject saveObject( MyComplexObject objectToSave ) {
MyComplexObject savedObject = daoInstance.saveObject( objectToSave );
return savedObject;
}
}
So you can see I'm autowiring a DAO object using spring, and then I use the DAO methods in the REST handlers.
The 'findObject' call seems to work fine - so far it works exactly as I expect it to.
The 'saveObject' call is not working the way I want and that's what I need some advice on.
You can see that I'm trying to directly take an instance of my complex object as a parameter to the REST method. Additionally I would like to return an instance of the complex object after it's been saved.
I put together some 'client' code for testing this out.
#Test
public void saveTest() {
WebResource wsClient = createWebServiceClient();
MyComplexObject unsavedInstance = createMyComplexObject();
MyComplexObject savedInstance =
wsClient
.path("saveObject")
.accept(MediaType.APPLICATION_XML)
.put(MyComplexObject.class, unsavedInstance);
assertNotNull(savedIntent);
}
Which is returning the following error:
com.sun.jersey.api.client.UniformInterfaceException: PUT http://localhost:8081/rest/myresource/save returned a response status of 400 Bad Request
I don't see why this isn't working and I think I've tried just about everything I can think of. Any help or direction would be very much appreciated.
Thanks so much!
I see that you call the accept() method in your test client (which means that a "Accept:" header is added to the request, indicating the server what type of representation you would like). However, you don't call the type() method to add a "Content-type:" header and inform the server that you are sending XML data. See http://jersey.java.net/nonav/documentation/latest/client-api.html#d4e644 for examples.
Side remark: your URLs are not RESTful - you should avoid verbs in your path:
So, instead of:
/api/findObject/{id}
/api/saveObject
You should use:
/api/objects/{id}
/api/objects
Last note: to create an object on calling /api/objects, you should do a POST and not a PUT to adhere to REST best practices and widely adopted patterns.
switching to the 'concrete class' solution I alluded to in my earlier comment is what fixed things up for me.