How to write single objectMapper for spring-data-rest and to my #RestController class - serialization

I wrote a UnwrappingBeanSerializer for my entity. Currently this serializer was registered using ConfigureJacksonObjectMapper
This serializer is working fine for REST APIs generated from spring-data-rest. But I have a custom #RestController for the same entity, But it doesn't know about the serializer registered in spring-data-rest configuration.
I want to serialize my response with UnwrappingBeanSerializer both in spring-data-rest APIs and also to my custom controllers.
How to achieve this?
I also tried with #JsonSerialize on my entity class. But I am unable to create bean for unWrappingBeanSerializer with BeanSerializerBase

Regular #RestController and Spring Data REST controllers have different flows and configuration. If you are using Spring Data REST, you'd better use #RepositoryRestController for custom endpoints of the same resource, this will use the same Spring Data REST chain and its configuration, like the one you used in ConfigureJacksonObjectMapper, otherwise your ObjectMapper is visible only for Spring Data REST.
If you want to have #RestController and use the same ObjectMapper for both - you need to have two configurations: one for Spring Data REST (like you already have) and another for regular controllers, so just register it in Spring context (for instance, if you are using Spring MVC, see Customize the Jackson ObjectMapper).

Related

Scale OpenAPI with common dependencies between services

Assume that there are two or more services with common models in their API specification and we use api first approach with OpenAPI.
To illustrate:
serviceA in its API definition has CommonModel
serviceB in its API definition has CommonModel
Where to define CommonModel?
in some distinct module and then ref it from all services using it
in one of the services and then ref it from all services using it
define it in each service and then resolve it during model
generation phase to avoid duplication conflicts
...
By service I mean different applications, api of each service auto-generated from OpenAPI spec
What is the best practices to scale and handle common model hell with OpenAPI approach?
In swagger hub there is feature called domains which is intended to reuse common models, params, etc. Idea to have commons in one place

JAX-RS: serializing a POJO fails on payara micro

After moving our application war from Glassfish3 to a deployment with Payara Micro, the JAX-RS serialization (jersey + jackson) doesn't work any more.
Thanks to Adam, we solved the issue with serializing pure collections, we now encounter similar errors when returning POJOs:
#GET
#Produces("application/json")
public BirdyTO findAllDaBirdy() {
return getBirdy();
}
where BirdyTO is a POJO which contains other POJOS and/or collections of POJOS.
That one gives us the error:
MessageBodyWriter not found for media type=application/json;charset=utf-8, type=class org.example.BirdyTO, genericType=class org.example.BirdyTO.
Strange thing is that similar interfaces in same application work fine.
Any idea?
Mapping of POJOs to JSON is not standardized in Java EE. Glassfih 4/Payara use MOXy to map POJO to JSON by default, which uses JAXB for the mapping. See [this post by Reza Rahman] (https://blogs.oracle.com/theaquarium/entry/moxy_is_the_new_default). It is possible that BirdyTO cannot be mapped by Moxy.
If you want to use Jackson, you have to:
disable default Moxy feature (by setting jersey.config.server.disableMoxyJson property to true)
add Jackson library into your app (com.fasterxml.jackson.jaxrs)
turn on the JacksonFeature (provided by the Jackson library) in your JAX-RS application
More info how to do it in this answer: Customizing JSON marhsalling with GlassFish v4

Class not found exception for WebMvcConfigurerAdapter, relevant class in Spring Data REST

I am new to Spring Data REST, I am not supported to use methods from spring-webmvc.jar. so I am planning to use #BasePathAwareController or #RepositoryRestController but I am seeing class not found exception for WebMvcConfigurerAdapter. I know that class is available in spring-webmvc.jar but how can I over come I can paste my Spring-config.xml and web.xml
I would like to find relevant class in Spring Data REST and how to configure that in Web.xml or dispatcher-servlet.xml.
I found RepositoryRestConfigurerAdapter similar to the WebMvcConfigurerAdapter class but not sure how to use it.

Request-scoped context field injections into RESTEasy singletons

While trying to embed RESTEasy with singleton resources in OSGi (using something similar to resteasy-osgi-bundle), to my surprise field-injected #Context UriInfo was available and valid on each request.
Digging deeper I found proxy magic and ThreadLocal in ResteasyProviderFactory. All well and good, but I cannot find any reference to such a behavior in docs, neither in RESTEasy's one nor in JAX-RS spec.
In Jersey docs we can find something like:
The exception exists for specific request objects which can injected even into constructor or class fields [of resources with singleton scope — OP]. For these objects the runtime will inject proxies which are able to simultaneously server more request. These request objects are HttpHeaders, Request, UriInfo, SecurityContext. These proxies can be injected using the #Context annotation.
How does it look in RESTEasy? Is the current implementation stable or experimental? What is the set of request-specific classes that can be injected into singletons?
It's not experimental. This behavior (for a set of common objects) is specified in the JAX-RS spec. There aren't any anchors in the spec page to link to a certain section, but where you should look is Chapter 5: Context. I'll post some snippet here.
5.1 Concurrency
Context is specific to a particular request but instances of certain JAX-RS components (providers and resource classes with a lifecycle other than per-request) may need to support multiple concurrent requests. When injecting an instance of one of the types listed in section 5.2, the instance supplied MUST be capable of selecting the correct context for a particular request. Use of a thread-local proxy is a common way to achieve this.
5.2 Context Types
This section describes the types of context available to resource classes, providers and Application subclasses.
5.2.1 Application
The instance of the application-supplied Application subclass can be injected into a class field or method parameter using the #Context annotation. Access to the Application subclass instance allows configuration information to be centralized in that class. Note that this cannot be injected into the Application subclass itself since this would create a circular dependency.
5.2.2 URIs and URI Templates
An instance of UriInfo can be injected into a class field or method parameter using the #Context annotation. UriInfo provides both static and dynamic, per-request information, about the components of a request URI. E.g. the following would return the names of any query parameters in a request:
5.2.3 Headers
An instance of HttpHeaders can be injected into a class field or method parameter using the #Context annotation. HttpHeaders provides access to request header information either in map form or via strongly typed convenience methods. E.g. the following would return the names of all the headers in a request:
5.2.4 Content Negotiation and Preconditions
JAX-RS simplifies support for content negotiation and preconditions using the Request interface. An instance of Request can be injected into a class field or method parameter using the #Context annotation. The methods of Request allow a caller to determine the best matching representation variant and to evaluate whether the current state of the resource matches any preconditions in the request...
5.2.5 Security Context
The SecurityContext interface provides access to information about the security context of the current request. An instance of SecurityContext can be injected into a class field or method parameter using the #Context annotation. The methods of SecurityContext provide access to the current user principal, information about roles assumed by the requester, whether the request arrived over a secure channel and the authentication scheme used.
5.2.6 Providers
The Providers interface allows for lookup of provider instances based on a set of search criteria. An instance of Providers can be injected into a class field or method parameter using the #Context annotation.
One thing to note is that there may more types that can be injected, but any not listed above would be implementation specific. Here is the list from the RESTeasy documentation in the section Chapter 15. #Context
The #Context annotation allows you to inject instances of javax.ws.rs.core.HttpHeaders, javax.ws.rs.core.UriInfo, javax.ws.rs.core.Request, javax.servlet.HttpServletRequest, javax.servlet.HttpServletResponse, javax.servlet.ServletConfig, javax.servlet.ServletContext, and javax.ws.rs.core.SecurityContext objects.
Though the documentation doesn't make any distinction between field and parameter injection, from what I remember, I think I was able to get HttpServletRequest injected into a field. But I would just test them all to make sure.

Add another UrlHandlerMapping to Spring data rest

I'm having a normal spring-mvc project and I'm also building a rest module as a separate jar file. The goal is when I have the rest jar in my classpath to have the normal website mapped to / and the spring-data-rest repositories mapped to /rest. For the rest module I have defined RepositoryRestMvcConfiguration as well as a WebApplicationInitializer and it all works fine.
So now I want to add some more URLs to the rest module (like /synchronize, and /authenticate, etc.) but as soon as I add controllers in the rest module, they are picked up by the parent application context (the one for the website /). I tried specifying them as bean in the RepositoryRestMvcConfiguration but still they are picked up by the other parent context and the filters of the parent context are fired. And when I access the spring-data-rest through /rest no filters are triggered.
So I was wondering: is there a method I could override in the RepositoryRestMvcConfiguration so that I can add extra url handler mappings?
I assume you mean that you want to have another controller advertised as part of Spring Data REST's root hypermedia.
To do so, you need to create another class in your app like this:
#Component
class DogifierResourceProcessor implements ResourceProcessor<RepositoryLinksResource> {
#Override
public RepositoryLinksResource process(RepositoryLinksResource objects) {
objects.add(new Link(ServletUriComponentsBuilder.fromCurrentRequest()
.build()
.toUriString()
.concat("dogifier/{id}"), "dogifier"));
return objects;
}
}
This will create a hypermedia entry with rel="dogifier" that lists /dogifier/{id} as the URI. It will also prefix it with the proper URN, etc.
Of course, you can use Spring HATEOAS to link to a controller method without having to specify the actual path by hand. That would reduce maintenance and encourage better hypermedia controls.
You need to exclude those controllers from the classpath scanning of the parent context. Just follow the instructions in the Spring documentation.