Is there any real light 4j examples for mapping json request to Java POJO objects? - light-4j

It happens to me that I am bound to use light 4j .
I couldn't find a simple example of a simple CRUD service in entire source code base of light 4j.
All there examples simply return dummy response in their handler.
None of them have actually injected a service and perform any logic .
Q1) Is anyone aware of any documentation or sample source code of light 4j which is complete in terms of CRUD operation including how to inject services with multiple implementation ?
PS : There documentation just display how to get ALL the implementations of a Service and not a SINGLE implementation out of many.
Q2) The actual question :
How to convert a very simple JSON Request body to a JAVA POJO object .
The worst of all possibility I found out is this .
Map<String, Object> bodyMap = (Map<String, Object>) exchange
.getAttachment(BodyHandler.REQUEST_BODY);
AccontRegisterRequest request = new AccontRegisterRequest();
request.setDob(LocalDate.parse((String) bodyMap.get("dob")));
request.setName((String) bodyMap.get("name"));
request.setInitialDeposite(
Float.parseFloat((String) bodyMap.get("initialDeposite")));
Request Payload
{
"name" : "Some Name",
"dob" : "1999-02-02",
"initialAmount" : 10000
}
Please dont recommend of adding a key in this JSON like this :
{
"somekey like body" : {
... and here goes by previous json
}
}
Because this BodyHandler is UN-NECESSARILY reading the input stream and converts it into a linkedHasMap.
So I cannot simply read the request input stream in my logic and pass it to JACKSON mapper to create my POJO.
Please help me to get me rid of this .

Sorry I didn't find this question in my previous scan.
You can convert a map to POJO with Jackson and it is very fast as there is no need to parse the JSON.
Take a look at this example in light-oauth2
https://github.com/networknt/light-oauth2/blob/master/client/src/main/java/com/networknt/oauth/client/handler/Oauth2ClientPostHandler.java#L44

Related

Access Spring WebClient response body **BEFORE** being parsed

I've got a problem with an URL call response encoding.
So, just before Spring's WebClient converts the body response into an String object, as desired, I need to access the raw body response to parse it with the proper encoding. So, just before:
<execution>.flatMap(servletResponse -> {
Mono<String> mono = servletResponse.bodyToMono(String.class);
}
I need to access the raw URL call response; I think before "flatMap".
So... I've been looking at "codecs" within Spring documentation, but... So; even for testing, I have:
myWriter is an instance of: EncoderHttpMessageWriter.
myReader is an instance of: DecoderHttpMessageReader.
myWriter handles myDecoder, an instance of Decoder.
myReader handles myEncoder, an instance of Encoder.
as per Spring Documentation about Codecs; and testing with both options for the WebClient Builder:
myWebClientBuilder = WebClient.Builder; // provided by Spring Context,
myWebClientBuilder = WebClient.builder(); // "by hand"
So, the relevant part of code looks like this (tried even with register and registerWithDefaultConfig):
WebClient.builder().codecs(consumer -> {
consumer.customCodecs().register(myWriter.getEncoder());
consumer.customCodecs().register(myWriter);
consumer.customCodecs().register(myReader.getDecoder());
consumer.customCodecs().register(myReader);
})
.build();
shows that the codecs load, and internal basic methods are called:
canDecode
canEncode
canRead
canWrite
getDecodableMimeTypes
getDecoder
getEncodableMimeTypes
getEncoder
but... No one of the read/write... Mono<T> / Flux<T> methods are used. Is there anything left for configuring a codec to properly parse the incoming response with the proper encoding?
The response is a String; a old-fashioned String, with all data-fields in a single row, that wll be parsed later, according to rules about positions and lengths of fields; nothing related with JSON or Jackson.
Is there another better way to perform this pre-action?
Many thanks in advance.

Mirror #RequestPart behavior in WebFlux functional router definitions with different content types

Problem
We're developing a Spring Boot service to upload data to different back end databases. The idea is that, in one multipart/form-data request a user will send a "model" (basically a file) and "modelMetadata" (which is JSON that defines an object of the same name in our code).
We got the below to work in the WebFlux annotated controller syntax, when the user sends the "modelMetadata" in the multipart form with the content-type of "application/json":
#PostMapping(consumes = [MediaType.MULTIPART_FORM_DATA_VALUE], produces = [MediaType.APPLICATION_JSON_VALUE])
fun saveModel(#RequestPart("modelMetadata") monoModelMetadata: Mono<ModelMetadata>,
#RequestPart("model") monoModel: Mono<FilePart>,
#RequestHeader headers: HttpHeaders) : Mono<ResponseEntity<ModelMetadata>> {
return modelService.saveModel(monoModelMetadata, monoModel, headers)
}
But we can't seem to figure out how to do the same thing in Webflux's functional router definition. Below are the relevant code snippets we have:
#Bean
fun modelRouter() = router {
accept(MediaType.MULTIPART_FORM_DATA).nest {
POST(ROOT, handler::saveModel)
}
}
fun saveModel(r: ServerRequest): Mono<ServerResponse> {
val headers = r.headers().asHttpHeaders()
val monoModelPart = r.multipartData().map { multiValueMap ->
it["model"] // What do we do with this List<Part!> to get a Mono<FilePart>
it["modelMetadata"] // What do we do with this List<Part!> to get a Mono<ModelMetadata>
}
From everything we've read, we should be able to replicate the same functionality found in the annotation controller syntax with the router functional syntax, but this particular aspect doesn't seem to be well documented. Our goal was to move over to use the new functional router syntax since this is a new application we're developing and there are some nice forward thinking features/benefits as described here.
What we've tried
Googling to the ends of the Earth for a relevant example
this is a similar question, but hasn't gained any traction and doesn't relate to our need to create an object from one piece of the multipart request data
this may be close to what we need for uploading the file component of our multipart request data, but doesn't handle the object creation from JSON
Tried looking at the #RequestPart annotation code to see how things are done on that side, there's a nice comment that seems to hint at how they are converting the parts to objects, but we weren't able to figure out where that code lives or any relevant example of how to use an HttpMessageConverter on the ``
the content of the part is passed through an {#link HttpMessageConverter} taking into consideration the 'Content-Type' header of the request part.
Any and all help would be appreciated! Even just some links for us to better understand Part/FilePart types and there role in multipart requests would be helpful!
I was able to come up with a solution to this issue using an autowired ObjectMapper. From the below solution I could turn the modelMetadata and modelPart into Monos to mirror the #RequestPart return types, but that seems ridiculous.
I was also able to solve this by creating a MappingJackson2HttpMessageConverter and turning the metadataDataBuffer into a MappingJacksonInputMessage, but this solution seemed better for our needs.
fun saveModel(r: ServerRequest): Mono<ServerResponse> {
val headers = r.headers().asHttpHeaders()
return r.multipartData().flatMap {
// We're only expecting one Part of each to come through...assuming we understand what these Parts are
if (it.getOrDefault("modelMetadata", listOf()).size == 1 && it.getOrDefault("model", listOf()).size == 1) {
val modelMetadataPart = it["modelMetadata"]!![0]
val modelPart = it["model"]!![0] as FilePart
modelMetadataPart
.content()
.map { metadataDataBuffer ->
// TODO: Only do this if the content is JSON?
objectMapper.readValue(metadataDataBuffer.asInputStream(), ModelMetadata::class.java)
}
.next() // We're only expecting one object to be serialized from the buffer
.flatMap { modelMetadata ->
// Function was updated to work without needing the Mono's of each type
// since we're mapping here
modelService.saveModel(modelMetadata, modelPart, headers)
}
}
else {
// Send bad request response message
}
}
Although this solution works, I feel like it's not as elegant as the one alluded to in the #RequestPart annotation comments. Thus I will accept this as the solution for now, but if someone has a better solution please let us know and I will accept it!

Project New Array Field with Spring Data

As part of an aggregate operation, I need to unwind an array. I am wondering how I can put the object back into an array as part of the project. Here is the MongoDB aggregate operation that works:
db.users.aggregate([ { "$match" : {...} , { "$unwind" : "$profiles"} ,{$project: {'profiles': ['$profiles']}}...}
And more specifically, how can I implement this using Spring Data mongoDB ProjectionOperation:
{$project: {'profiles': ['$profiles']}}
This feature has been added since 3.2.
Edit 1:
I looked through some of the posts and one answer by
Christoph Strobl:
and based on the answer I came up with something that works which is as follows:
AggregationOperation project = aggregationOperationContext -> {
Document projection = new Document();
projection.put("profiles", Arrays.<Object> asList("$profiles"));
projection.put("_id","$id");
return new Document("$project", projection);
};
I am wondering if there is a better way of doing it though.
Any help/suggestion is very much appreciated. Thanks.
Unfortunately there is not.
You can replace $project by project() with an AggregationExpression to shorten it a bit.
// ...
unwind("profiles"),
project().and(ctx -> new Document("profiles", asList("$profiles"))).as("profiles")
I created DATAMONGO-2312 to provide support for new array field projections in one of the next versions.

Is there any way to implement pagination in spring webflux and spring data reactive

I'm trying to understand reactive part of spring 5. I have created simple rest endpoint for finding all entities using spring web-flux and spring data reactive (mongo) but don't see any way how to implement pagination.
Here is my simple example in Kotlin:
#GetMapping("/posts/")
fun getAllPosts() = postRepository.findAll()
Does it mean that reactive endpoint does not require pagination? Is some way to implement pagination from server side using this stack?
The reactive support in Spring Data does not provide means of a Page return type. Still, the Pageable parameter is supported in method signatures passing on limit and offset to the drivers and therefore the store itself, returning a Flux<T> that emits the range requested.
Flux<Person> findByFirstname(String firstname, Pageable pageable);
For more information please have a look at the current Reference Documentation for 2.0.RC2 and the Spring Data Examples.
Flux provides skip and take methods to get pagination support, and you also can use filter and sort to filter and sort the result. The filter and sort below is not a good example, but use skip and Pageable as 2nd parameter are no different.
The following codes work for me.
#GetMapping("")
public Flux<Post> all(
//#RequestParam(value = "q", required = false) String q,
#RequestParam(value = "page", defaultValue = "0") long page,
#RequestParam(value = "size", defaultValue = "10") long size) {
return this.postRepository.findAll()
//.filter(p -> Optional.ofNullable(q).map(key -> p.getTitle().contains(key) || p.getContent().contains(key)).orElse(true))//(replace this with query parameters)
.sort(comparing(Post::getCreatedDate).reversed())
.skip(page * size).take(size);
}
Update: The underlay drivers should be responsible for handling the result in the reactivestreams way.
And as you see in the answer from Christoph, if using a findByXXX method, Spring Data Mongo Reactive provides a variant to accept a pageable argument, but the findAll(reactive version) does not include such a variant, you have to do skip in the later operations if you really need the pagination feature. When switching to Flux instead of List, imagine the data in Flux as living water in the rivers or oil in the pipes, or the tweets in twitter.com.
I have tried to compare the queries using Pageale and not in the following case.
this.postRepository.findByTitleContains("title")
.skip(0)
.limitRequest(10)
.sort((o1, o2) -> o1.getTitle().compareTo(o2.getTitle()))
this.postRepository.findByTitleContains("title", PageRequest.of(0, 10, Sort.by(Sort.Direction.ASC, "title")))
When enabling logging for logging.level.org.springframework.data.mongodb.core.ReactiveMongoTemplate=DEBUG and found they print the same log for queries.
find using query: { "title" : { "$regularExpression" : { "pattern" : ".*title.*", "options" : ""}}} fields: Document{{title=1}} for class: class com.example.demo.Post in collection: post
//other logging...
find using query: { "title" : { "$regularExpression" : { "pattern" : ".*title.*", "options" : ""}}} fields: Document{{title=1}} for class: class com.example.demo.Post in collection: post
Keep in mind, all these operations should be DELEGATED to the underlay R2dbc drivers which implemented the reactive streams spec and performed on the DB side, NOT in the memory of your application side.
Check the example codes.
The early sample code I provided above maybe is not a good sample of filter and sort operations(MongoDB itself provides great regularexpression operations for it). But pagination in the reactive variant is not a good match with the concept in the reactive stream spec. When embracing Spring reactive stack, most of the time, we just move our work to a new collection of APIs. In my opinion, the realtime update and elastic response scene could be better match Reactive, eg. using it with SSE, Websocket, RSocket, application/stream+json(missing in the new Spring docs) protocols, etc
This is not efficient but it works for me while I look for another solution
Service
public Page<Level> getPage(int page, int size, Sort.Direction direction, String properties) {
var pageRequest = PageRequest.of(page, size, direction, properties);
var count = levelRepository.count().block();
var levels = levelRepository.findAllLevelsPaged(pageRequest).collectList().block();
return new PageImpl<>(Objects.requireNonNull(levels), pageRequest, Objects.requireNonNull(count));
}
Repo
#Repository
public interface LevelRepository extends ReactiveMongoRepository<Level, String> {
#Query("{ id: { $exists: true }}")
Flux<Level> findAllLevelsPaged(final Pageable page);
}
Ref example

Akka Futures + Spring MVC deferred results + tomcat 7.+

Spring-api 3.+ onwards introduces support aync request processing, So I thought of putting it to sample webapplication with my favourite concurrency model provided by Akka
my code looks something like this
#RequestMapping(value = Array("/"), method = Array(RequestMethod.GET))
#ResponseBody
def adminHome(request: HttpServletRequest) : DeferredResult[ModelAndView] = {
import ExecutionContext.Implicits.global
val result = new DeferredResult[ModelAndView]
........ code for some future .........
// creating model map future from some future
val modelMapFuture: Future[Map[String, Any]] = someFuture.flatMap(urlObjects =>
Future(
Map("urlList" -> urlObjects.asJava)
))
// setting the deferred result value upon completion of future
modelMapFuture.onComplete {
case Success(modelMap) => result.setResult(new ModelAndView("index", modelMap.asJava))
case Failure(e) => result.setResult(new ModelAndView("index"))
}
result
}
I have enable the aync support for Spring mvc DispatcherServelet and all the Filters attached to the url mapping of particular servelet.
But all the time I'm getting an empty page as the result.
I can help you to narrow down the problem by saying -
a. No exception in model/view
If I set view as a simple JSP with hello world, its also not loading.
b. Request mapping is working perfectly
c. Future gets completed without errors
d. Deffered result is set properly
I have bind a DeferredResultProcessingInterceptorAdapter implementation to the mvc:deferred-result-interceptors and put logs for beforeConcurrentHandling, preProcess, postProcess and afterCompletion
I'm getting following logs from the interceptor
Before concurrent handling request : deffered result expired or set is : false
pre process : deffered result expired or set is : false
post process : deffered result expired or set is : true
after completion : deffered result expired or set is : true
Any help will be highly appriciated as I was strugging with this for entire two days.
More details
Spring version 3.2.3-RELEASE
Tomcat version 7.0.42
I don't think you should be using #ResponseBody in conjunction with ModelAndView. #ResponseBody would be used if you were simply returning some data -- something like DeferredResult[List[String]].

Resources