Spring + Swagger2 + HashMap JSON - java

I have a service that has a HashMap receiving the json from the client
public ResponseEntity<?> trocarSenha(#RequestBody HashMap<String, String> json)
Is there any way to tell to swagger what I expect receive? I would like Swagger show something like this

In your case, assuming it's a fixed set of attributes your expecting, I would recommend using #ModelAttribute instead of #ResponseBody and using a concrete bean class with the getters and setters for the properties you wish to expose.
The catch is if u want to add additional properties that are not visible to the consumer but only to the server u might have to do some work.
NOTE: if the properties you wish to add are not conforming the bean spec (getters & setters) it will not be included.

Related

set header on rsocket messages with spring boot

so I've started playing with rsocket and spring boot 2.2 to see if I can use it in my projects, but I'm facing a bit of troubles.
Normally, with spring messaging I define a listener method like the following:
#MessageMapping("addGeolocation")
public Mono<Boolean> addGeolocation(#Header("metadata") MmeMetadata metadata, #Payload String geolocation) { ... }
My understanding is that with rsocket I should be able to use the same logic, but when I'm defining the client I couldn't find an easy way to set message headers.
Currently I'm stuck with this:
boolean outcome = rSocketRequester.route("addGeolocation").metadata(...?).data(geolocationWKT).block();
is the metadata a replacement for headers? that method signature seems a little too generic to be used like headers. If I put an Map in it will spring be able to decode headers out of it?
Thank you,
Fernando
Please see this question: RSocket Metadata - custom object.
I used it as a starting point for my solution.
The term 'header' actually means some custom metadata. So, in order to get the correct value you need to configure metadataExtractorRegistry. For Spring Boot do it this way (code in kotlin):
val CUSTOM_MIMETYPE = MimeType.valueOf("<some custom mime type>")
val CUSTOM_HEADER = "<the name of a header>"
...
#Bean
fun rSocketStrategiesCustomizer(): RSocketStrategiesCustomizer {
return RSocketStrategiesCustomizer { strategies: RSocketStrategies.Builder ->
strategies.metadataExtractorRegistry {
it.metadataToExtract(CUSTOM_MIMETYPE, String::class.java, CUSTOM_HEADER)
}
}
}
The type of the data object can be any, not necessarily a String. There is default String endcoder/decoder, so I didn't provide one in the code. For your own type you can provide one of existing encoders/decoders (Json for example) or create your own:
#Bean
fun rSocketStrategiesCustomizer(): RSocketStrategiesCustomizer {
return RSocketStrategiesCustomizer { strategies: RSocketStrategies.Builder ->
strategies.metadataExtractorRegistry {
it.metadataToExtract(CUSTOM_MIMETYPE, YourType::class.java, CUSTOM_HEADER)
}.decoder(Jackson2JsonDecoder())
.encoder(Jackson2JsonEncoder())
}
}
After you've configured registry as above, use the header name defined in the registry in your controller:
#MessageMapping("addGeolocation")
public Mono<Boolean> addGeolocation(#Header(CUSTOM_HEADER) String metadata, #Payload String geolocation) { ... }
And in order to send that header, use next code:
boolean outcome = rSocketRequester.route("addGeolocation")
.metadata("value", CUSTOM_MIMETYPE)
.data(geolocationWKT)
.block();
Hope this helps
Instead of a bag of name-value pairs (i.e. headers), RSocket uses metadata which can be in any format (i.e. MIME type) and it can be composite metadata with multiple types of metadata each formatted differently. So you can have one section with routing metadata, another with security, yet another with tracing, and so on.
To achieve something similar to headers, you can send name-value pairs as JSON-formatted metadata. Now on the server side, you'll need to provide a hint to Spring for how to extract a Map (of headers) from the metadata of incoming requests. To do that you can configure a MetadataExtractor and that's described in this section of the docs. Once that's configured, the extracted Map becomes the headers of the message and can be accessed from #MessageMapping methods as usual (via MessageHeaders, #Header, etc).

Spring MVC Binding Request parameters to POJO fields

I want a controller with the following mapping (incomplete):
#GetMapping(/searchitems)
public #ResponseBody Page<Item> get(Item probe)
From the Item probe parameter I want to query by example in a repository of items and return the result.
Question:
How can I complete the mapping above for a search URL? As search URL I was thinking something like /searchitems?itemAttributeA=foo&itemAttributeB=bar&...itemAttributeZ=xyz. How can I tell spring to inject the passed request parameters into the Item probe fields with the same names?
Adding #ModelAttribute should bind the individual request parameters into your Item POJO.
public #ResponseBody Page<Item> get(#ModelAttribute Item probe)
You can create a POJO and pass as a parameter in the controller class. Pojo should have the fields which you want to read and set. Spring will read and map those attributes in the Pojo which you will define as the request.
#GetMapping(/searchitems)
public ResponseEntity<List<Items>> searchItems(ItemRequest itemRequest) {
}
Only thing needs to be taken care is to check for binding result. If there are errors, we need to stop the request and handle or throw.
For e.g. All of the below attributes in the URL will be set in the Pojo.
https://domain/search-items?pageNumber=1&sortOrder=ascending&itemName=test&itemType=apparel&sortField=itemId&pageSize=5
You can use #RequestParam for this.
public #ResponseBody Page<Item> get(#RequestParam("itemAttributeA") String itemAttributeA ,
#RequestParam("itemAttributeB") String itemAttributeB,...)

Angular JS & Spring REST -How to Convert JSON Model object to HttpServletRequest for a legacy app

I need to work on an enterprise legacy Java application that is developed in servlets & jsp's.Planning to convert this legacy app to a Single Page application using angular js & Spring MVC REST.
In the new development, AngularJS will be submitting the model object's (as JSON ) to Spring REST methods.
In the existing application there is a lot of code in servlets and classes (at least 2000 lines in 30 classes) written to get request parameter's using HttpServletRequest i.e., request.getParameter("name");
Is it possible to be able to inject/convert the model (JSON) object submitted by angularJs to Spring MVC REST methods into HttpServletRequest object, so that I need not change all the legacy code & classes?
Not considering to use the #RequestParam annotation in the method signature as the number of parameters are high.
Whatever JSON Object you are defining like below and which you trying to pass backend
var dataToPass={
name:"XYZ",
id:12,
selstat:[12,14]
};
For that, you need to create JAVA POJO with similar name like below
class UIData{
private String name; // Getter and Setter
private Integer id; // Getter and Setter
private List<Integer> selstat; // Getter and Setter
}
And in Spring while defining mapping in controller, you need to use annotation #ResuestBody in argument like below
#RequestMapping(value ='/mappingURL', method = RequestMethod.POST)
public #ResponseBody RsponseObject processData(#RequestBody UIData uiData, HttpServletRequest request)
throws MyException {
// Process you data
}
This will automatically convert JSON object into POJO instance.
Please go through Spring Documentation for more details.
And make sure content-type in header while passing is application/json along with Jackson library added in your dependency.

How to get Spring 3.2's ConversionService and HttpMessageConverters to work together for #RequestBody annotation?

Before AJAX was popular, it was possible to convert between id's and entities by using a custom property editor and registering that in your controllers. So if you had a User form backing object that contained a Company, if company.id was 5, Spring would call your custom property editor to so that you could go fetch the Company with id 5 and set it onto your user.company property.
Now in the Ajax way of doing things, we have similar requirements. Instead of using a form backing object, we want to do an HTTP POST or PUT of a User object as JSON data and have Spring automatically convert that JSON to a User object on our behalf. Spring has made this possible with the #RequestBody annotation, and by using Jackson to marshall the JSON back and forth to Java objects.
This is just a fictitious example. Imagine a User containing a Company object with the appropriate getters/setters.
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.NO_CONTENT)
public void create(#Valid #RequestBody User user) {
userService.saveUser(user);
}
Since property editors are a thing of the past as far as Spring is concerned, we are expected to use the new Conversion Service API. For my application, I have successfully created a factory that does what my old property editor did before - converting id's back to entities.
My question is, how can I get Spring to call into the conversion service during or after Jackson marshals the JSON data? I know it is possible to create a custom JsonDeserializer, but I find writing/testing these to be a pain and lengthy process as I need to do it for a massive number of entities, and each deserializer would take anywhere from 60 to 200 lines of code each.
I'd love it if Spring could do the id to entity mapping for me on my behalf, just as it did for form backing objects. Is there a way?
It will only work the root object User in this case it will not work for nested components. Spring Data REST has a `DomainClassConverter' which you can take a look at.
Basically you want to create ConditionalGenericConverter which checks if it can convert the requested object (i.e. can it be loaded by the EntityManager/SessionFactory). (A non-conditional version is here.
This all goes a bit against REST (basically) to do the lookup on the serverside as you should be sending everything needed with the request (Representational State Transfer and Hypermedia as Transfer Engine of All State). But that is for another discussion :) .
Links
Domain Entity Converter blog
Spring Reference guide
The M. Deinum's answer was great.
But for a practical work , think about AOP ;)
It can be interesting to use it in your problem :).

Spring MVC Controller pre process request body

I am working on spring REST APIs. In requirements, there are 2 POST requests with same URL but different request body. Since Spring MVC must have unique mappings across controller, I have to pre-process the request body to map to a specific POJO.
On the basis of session_type in request body, I have to map the request to specific POJO (JSON -> JAVA POJO).
For example, if 'session_type' in request body is 'typeX' then the request should map to ClassX POJO. If 'session_type' in request body is 'typeY' then the request should map to ClassY POJO.
If there a way to do it using some kind of requestbody annotation?
If you want to bind typeX and typeY, then you definitely need 2 handlers. But, why wouldn't we use param option of #RequestMapping:
#RequestMapping(method = RequestMethod.POST,
value = "/url", params = "session_type=typeX")
public String handleTypeX(#RequestBody #ModelAttribute TypeX typeX){
//TODO implement
}
#RequestMapping(method = RequestMethod.POST,
value = "/url", params = "session_type=typeY")
public String handleTypeY(#RequestBody #ModelAttribute TypeY typeY){
//TODO implement
}
If you need some preparations (f.e. normalize params or perform model binding manually), then the approach above you may combine along with #InitBinder, but please note, that #InitBinder needs exact ULR's rules along with #ModelAttribute parameters in handlers.
EDIT: In Spring MVC there is no possibility to use 2 handlers for exact URL, i.e. when method/URL/params/consumes type are the same.
Thus I suggest use unified handler, where you would check necessary parameter and then manually convert into corresponding class. For finding necessary class I suppose it would be better to use Strategy pattern:
//class resolver according "session_type" parameter
//note, that you can use Spring autowiring capabilities
private final Map<String, Class> TYPES_CONTEXT = new HashMap<String, Class>(){
{
this.put("x", TypeX.class);
this.put("y", TypeY.class);
//TODO probably other classes
}
}
#RequestMapping(method = RequestMethod.POST,
value = "/url")
public #ResponseBody String handleAnyType(#RequestBody Map<String, String> body){
String sessionType = body.get("session_type");
//TODO handle case if sessionType is NULL
Class convertedClass = TYPES_CONTEXT.get(sessionType);
//TODO handle case if class is not found
Object actualObject = objectMapper.convertValue(body, convertedClass);
//now we use reflection for actual handlers, but you may refactor this in the way you want, f.e. again with Strategy pattern
//note that current approach there should be contract for methods names
Method actualHandler = this.getClass().getMethod("handle" + actualObject.getClass().getSimpleName());
return (String)actualHandler.invoke(this, actualObject);
}
public String handleTypeX(TypeX typeX){
//TODO implement
}
public String handleTypeY(TypeY typeY){
//TODO implement
}
//TODO probably other methods
This approach doesn't handle validation and some things were omitted, but I believe this might be helpful.
I think you should created controller with one method for both types, and call required component\method in it depending on typeX or typeY.
GETs shouldn't have request bodies, or at least if they do, the server side isn't required to do anything with them. As you describe it, this API isn't RESTful.
Assuming you don't care about that, try creating a controller method that takes a parent class of TypeX and TypeY, or interface that both TypeX and TypeY implement, annotate it with #SomethingMeaningfulToYou, then use a web argument method resolver to instantiate the child class you want.
It's a hack around a broken API though.
there are 2 POST requests with same URL but different request body
For a RESTful interface, the same URL should always indicate the same resource. The body of a request may contain different representations of that resource. You could create different HttpMessageContverter classes for the two different kinds of representation.

Categories