Use Generics/Patterns in Java for object mapping - java

I have a proxy service which exposes several APIs - each requesting an Object of a specific type and returning an Object of a specific type. Requests come to my ProxyService which are mapped to the format expected by the underlying service:
public class ProxyService {
public ProxyServiceResponse_A performA(ProxyServiceRequest_A request);
public ProxyServiceResponse_B performB(ProxyServiceRequest_B request);
public ProxyServiceResponse_C performC(ProxyServiceRequest_C request);
...
}
public class ProxiedService {
public ProxiedServiceResponse_A performA(ProxiedServiceRequest_A request);
public ProxiedServiceResponse_B performB(ProxiedServiceRequest_B request);
public ProxiedServiceResponse_C performC(ProxiedServiceRequest_C request);
...
}
I want to create generic mappers for mapping incoming ProxyService requests to ProxiedService requests:
public class MyRequestMapper {
public ProxiedServiceRequest_A mapRequestA(ProxyServiceRequest_A request);
...
}
I know of dozer and apache-velocity but I don't want to use those, instead do this on my own. Is there a design pattern or a generic way to achieve this?

You might consider a generic interface.
interface RequestMapper<T, U> {
U mapRequest(T request);
}
class ARequestMapper implements RequestMapper<ProxyServiceRequest_A, ProxiedServiceRequest_A> {
#Override
public ProxiedServiceRequest_A mapRequest(ProxyServiceRequest_A request) {
//TODO
}
}
class BRequestMapper implements RequestMapper<ProxyServiceRequest_B, ProxiedServiceRequest_B> {
#Override
public ProxiedServiceRequest_B mapRequest(ProxyServiceRequest_B request) {
//TODO
}
}

Related

Create a convenience decorator to generate a Controller from a function using BeanPostProcessor?

I'm looking to write a decorator that takes a very static function and wraps it inside a controller.
Think of it as a global scope utility callable/runnable, so pathvariable/requestbody has to be injected into the parameters. And then it has to automatically be wrapped inside a bean controller with the appropriate getmapping/postmapping to expose it an endpoint
#AutoGetMapping("/users/{id}")
public ResponseEntity<User> getById(#PathVariable long id) {
Optional<User> user = userService.getById(id);
if (user.isPresent()) {
return new ResponseEntity<>(user.get(), HttpStatus.OK);
} else {
throw new RecordNotFoundException();
}
}
gets transformed to
#RestController
public class UserController {
#Autowired
UserService userService;
#GetMapping("users")
public ResponseEntity<List<User>> getAll() {
return new ResponseEntity<>(userService.getAll(), HttpStatus.OK);
}
#GetMapping("users/{id}")
public ResponseEntity<User> getById(#PathVariable long id) {
Optional<User> user = userService.getById(id);
if (user.isPresent()) {
return new ResponseEntity<>(user.get(), HttpStatus.OK);
} else {
throw new RecordNotFoundException();
}
}
}
(maybe even the service layers).
I'm just looking for a place to start. I think im making a mistake in trying to use BeanPostProcessor and BeanDefinitionRegistryPostProcessor to do this. Can someone point me in the right direction on how to start doing this ?
One way to do it could be using the approach described in Interface Driven Controllers article with some additions.
As in the article, we can create an interface with the default annotations. Additionally, we can implement the default methods and enforce the implementation of the certain methods in the service layer using some generics like this:
#RestController
#RequestMapping("/default")
public interface BasicRestController<ID, T, S extends BasicRestService<T, ID>> {
#NonNull S getService();
#GetMapping("/{id}")
default ResponseEntity<T> getById(#PathVariable ID id) {
return getService().getById(id)
.map(ResponseEntity::ok)
.orElseThrow(RecordNotFoundException::new);
}
#GetMapping
default ResponseEntity<List<T>> getAll() {
List<T> results = getService().getAll();
return ResponseEntity.ok(results);
}
}
public interface BasicRestService<T, ID> {
Optional<T> getById(ID id);
List<T> getAll();
}
And then use it in the controller like this:
#RestController
#RequestMapping("/bars")
#RequiredArgsConstructor
public class BarController implements BasicRestController<Long, Bar, BarService> {
private final BarService barService;
#Override
public #NonNull BarService getService() {
return barService;
}
}
Minimal working example can be found here: https://bitbucket.org/kasptom/stack-73744318-interface-driven-controller

How to set HttpHeaders data to every Custom Request Class in WebFlux APIS?

In my APIs, there is custom request class for each APIs, I want to write code which gets fields from HttpHeaders from upcoming request and set that set of fields to that particular Request class, so it will do this for all request classes.
I have done this in MVC code, but don't know how to do this for reactive APIs with WebFlux(Library- Project Reactor).
Controller:
public Mono<ResponseEntity<JsonNode>> getData(#RequestHeader HttpHeaders header, GetDataRequest request){
.... // all stuff
}
now some data are coming from header like type, token, comID, etc.
I want to set these fields to Request Class GetDataRequest before further processing of the request as I will need these fields further,
but this request class different for all the requests, so I need common code, which set this to any request class which is passed to it.
Note: not using WebClient here, only Flux and Mono are there.
So basically, get fields from a header which is of type HttpHeaders, set these data to particular request class, but do this in WebFlux Framework, reactive APIS.
Please help anyone.
I would do the following:
define some base class for your requests that would have attributes you want to store headers values in, e.g.:
public class MyAbstractRequest {
private String header1;
private String header2;
// ...
// getters and setters
}
inherit all you request classes from this class, e.g.:
public class GetDataRequest extends MyAbstractRequest {
// GetDataRequest content here
}
create an argumentResolver for all those classes that inherit from MyAbstractRequest. To ensure the behavior is same as for normal request body deserialization use AbstractMessageReaderArgumentResolver as a base class:
public class MyArgumentResolver extends AbstractMessageReaderArgumentResolver {
public MyArgumentResolver(List<HttpMessageReader<?>> messageReaders, ReactiveAdapterRegistry adapterRegistry) {
super(messageReaders, adapterRegistry);
}
#Override
public boolean supportsParameter(MethodParameter parameter) {
return MyAbstractRequest.class.isAssignableFrom(parameter.getParameterType());
}
#Override
public Mono<Object> resolveArgument(MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange) {
return readBody(parameter, true, bindingContext, exchange)
.map(o -> {
// your headers extraction logic here ...
((MyAbstractRequest) o).setHeader1(exchange.getRequest().getHeaders().getFirst("header1"));
((MyAbstractRequest) o).setHeader2(exchange.getRequest().getHeaders().getFirst("header2"));
return o;
});
}
}
configure your MyArgumentResolver in the webflux configuration:
#Configuration
public class WebFluxConfiguration implements WebFluxConfigurer {
#Autowired
ApplicationContext applicationContext;
#Override
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
ServerCodecConfigurer serverCodecConfigurer = applicationContext.getBean(ServerCodecConfigurer.class);
ReactiveAdapterRegistry reactiveAdapterRegistry = applicationContext.getBean("webFluxAdapterRegistry", ReactiveAdapterRegistry.class);
configurer.addCustomResolver(new MyArgumentResolver(serverCodecConfigurer.getReaders(), reactiveAdapterRegistry));
}
}
Now your requests should get injected into the controller methods with the configured resolver:
public Mono<ResponseEntity<JsonNode>> getData(GetDataRequest request){
}

How can I instantiate a specific sub-type for a #RequestBody parameter based on the requested URI for a Spring MVC controller method?

Given the following basic domain model:
abstract class BaseData { ... }
class DataA extends BaseData { ... }
class DataB extends BaseData { ... }
I want to write a Spring MVC controller endpoint thus ...
#PostMapping(path="/{typeOfData}", ...)
ResponseEntity<Void> postData(#RequestBody BaseData baseData) { ... }
The required concrete type of baseData can be inferred from the typeOfData in the path.
This allows me to have a single method that can handle multiple URLs with different body payloads. I would have a concrete type for each payload but I don't want to have to create multiple controller methods that all do the same thing (albeit each would do very little).
The challenge that I am facing is how to "inform" the deserialization process so that the correct concrete type is instantiated.
I can think of two ways to do this.
First use a custom HttpMessageConverter ...
#Bean
HttpMessageConverter httpMessageConverter() {
return new MappingJackson2HttpMessageConverter() {
#Override
public Object read(final Type type, final Class<?> contextClass, final HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
// TODO How can I set this dynamically ?
final Type subType = DataA.class;
return super.read(subType, contextClass, inputMessage);
}
};
}
... which gives me the challenge to determine the subType based on the HttpInputMessage. Possibly I could use a Filter to set a custom header earlier when the URL is available to me, or I could use a ThreadLocal also set via a Filter. Neither sounds ideal to me.
My second approach would be to again use a Filter and this time wrap the incoming payload in an outer object which would then provide the type in a way that enables Jackson to do the work via #JsonTypeInfo. At the moment this is probably my preferred approach.
I have investigated HandlerMethodArgumentResolver but if I try to register a custom one it is registered AFTER the RequestResponseBodyMethodProcessor and that class takes priority.
Hmm, so after typing all of that out I had a quick check of something in the RequestResponseBodyMethodProcessor before posting the question and found another avenue to explore, which worked neatly.
Excuse the #Configuration / #RestController / WebMvcConfigurer mash-up and public fields, all for brevity. Here's what worked for me and achieved exactly what I wanted:
#Configuration
#RestController
#RequestMapping("/dummy")
public class DummyController implements WebMvcConfigurer {
#Target(ElementType.PARAMETER)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#interface BaseData {}
public static class AbstractBaseData {}
public static class DataA extends AbstractBaseData {
public String a;
}
public static class DataB extends AbstractBaseData {
public String b;
}
private final MappingJackson2HttpMessageConverter converter;
DummyController(final MappingJackson2HttpMessageConverter converter) {
this.converter = converter;
}
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(
new RequestResponseBodyMethodProcessor(Collections.singletonList(converter)) {
#Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(BaseData.class)
&& parameter.getParameterType() == AbstractBaseData.class;
}
#Override
protected <T> Object readWithMessageConverters(
NativeWebRequest webRequest, MethodParameter parameter, Type paramType)
throws IOException, HttpMediaTypeNotSupportedException,
HttpMessageNotReadableException {
final String uri =
webRequest.getNativeRequest(HttpServletRequest.class).getRequestURI();
return super.readWithMessageConverters(
webRequest, parameter, determineActualType(webRequest, uri));
}
private Type determineActualType(NativeWebRequest webRequest, String uri) {
if (uri.endsWith("data-a")) {
return DataA.class;
} else if (uri.endsWith("data-b")) {
return DataB.class;
}
throw new HttpMessageNotReadableException(
"Unable to determine actual type for request URI",
new ServletServerHttpRequest(
webRequest.getNativeRequest(HttpServletRequest.class)));
}
});
}
#PostMapping(
path = "/{type}",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<? extends AbstractBaseData> post(#BaseData AbstractBaseData baseData) {
return ResponseEntity.ok(baseData);
}
}
The key to this is that I stopped using #RequestBody because that is what was preventing me overriding the built-in behaviour. By using #BaseData instead I get a HandlerMethodArgumentResolver that uniquely supports the parameter.
Other than that it was a case of assembling the two objects that already did what I needed, so autowire a MappingJackson2HttpMessageConverter and instantiate a RequestResponseBodyMethodProcessor with that one converter. Then pick the right method to override so that I could control what parameter type was used at a point that I had access to the URI.
Quick test. Given the following payload for both requests ...
{
"a": "A",
"b": "B"
}
POST http://localhost:8081/dummy/data-a
... gives a response of ...
{
"a": "A"
}
POST http://localhost:8081/dummy/data-b
... gives a response of ...
{
"b": "B"
}
In our real-world example this means that we will be able to write one method each that supports the POST / PUT. We need to build the objects and configure the validation possibly - or alternatively if we use OpenAPI 3.0 which we are investigating we could generate the model and validate without writing any further code ... but that's a separate task ;)

how to inject headers in a `#context HttpServletRequest`?

Let's say I have this code:
#ApplicationPath("...")
public class MyApp extends ResourceConfig {
public SalesLayerApplication() {
this.register(HeaderInjecterFilter.class);
this.register(Test.class);
}
}
#PreMatching
public class HeaderInjecterFilter implements ContainerRequestFilter {
#Override
public void filter(final ContainerRequestContext crc) throws IOException {
crc.getHeaders().add("foo", "bar");
}
}
#Path("/test")
public class Test {
#GET
#Produces(MediaType.TEXT_PLAIN)
public String dump(#Context final HttpServletRequest request) {
return request.getHeader("foo");
}
}
I was expecting to call the rest entry point /test and to retrieve the string bar.
But all I see is null
If I use #HeaderParam("foo") I correctly retrieve the variable, but I need to access throug the #Context HttpServletRequest.
Why would you expect that adding headers to the ContainerRequestContext would also add it to the HttpServletRequest? These are completely unrelated entities. Try injecting HttpHeaders or you can also inject the ContainerRequestContext directly.

Interfaces declaring methods with abstracts as parameters

I have this question about best practices in following examples:
interface Request;
interface Service {
void process(Request request)
}
class MyService implements Service;
class YourService implements Service;
class MyRequest implements Request;
class YourRequest implements Request;
But how to ensure that MyService will always receive MyRequest and YourService will get YourRequest only, and not in the opposite way? Obvious answer "if-instance-of-check" in MyService.process(...) seems ugly and somehow against SOLID principles. Maybe there are better ways around?
Maybe generics would be good solution? (But then, how to use them in code that has to run under Java 1.4?)
Put simply, you are establishing an interface that you then don't want to adhere to, so it's not really an ideal design.
What I mean is, if MyService implements Service, then it must be able to take any kind of request. Otherwise it isn't following the defined contract.
I would question why you have the Service interface at all in this instance, and if you do need it (for other methods) whether it's appropriate for the process(Request request) method to be on there if subclasses are not going to honour it.
If the design of the contract is that each Service can process any kind of Request, then your implementation of MyService , which only takes MyRequest (and breaks if other kinds of Requests are passed in), is wrong.
If the design of the contract is that Service and Request subclasses maps to each other, e.g., MyService can (and should) only process a MyRequest, then you will need to change the interface of Service. Otherwise, the current interface as written in the question does not do what the question describes it to do. One way to fix is to parameterize the Service interface:
interface Service<R> {
void process(R request);
}
then your concrete MyService will be
public class MyService implements Service<MyRequest> {
public void process (MyRequest r) {/*blah*/}
}
You can see an example of this in action in the JDK - the Comparator interface does exactly this, for exactly the same reason. http://java.sun.com/javase/6/docs/api/java/util/Comparator.html
I cant see why you would, but if you still want to restrict the hierachy of MyRequest to be a request, then you can swap Service<R> with Service<R extends Request>
edit: this obviously doesnt run in 1.4, so to do the same thing[1] , you will need to use a visitor pattern. Its uglier, but 1.4 is ugly =)
interface Service {
void process(Request visitor);
}
interface RequestVisitor {
void visitMyRequest(MyService service);
void visitYourRequest(YourService service);
void visitTheOtherRequest(TheOtherService service);
}
interface Request extends RequestVisitor { /* and any extra methods required for request*/ }
public class MyService implements Service {
public process(Request r) {r.visitMyRequest(this);}
public void doSpecialMyProcessing(MyRequest request) { /* your code using MyRequest*/ }
}
public class YourService implements Service {
public process(Request r) {r.visitYourRequest(this);}
public void doSpecialYourProcessing(YourRequest request) { /* your code using YourRequest */ }
}
public class MyRequest implements Request {
void visitMyRequest(MyService service) {
service.doSpecialMyProcessing(this);
}
void visitYourRequest(YourService service) {
throw new UnsupportedOperation("Cannot call visitYourRequest in MyRequest!");
}
void visitTheOtherRequest(TheOtherService service) {
throw new UnsupportedOperation("Cannot call visitTheOtherRequest in MyRequest!");
}
}
public class YourRequest implements Request {
void visitMyRequest(MyService service) {
throw new UnsupportedOperation("Cannot call visitMyRequest in YourRequest !");
}
void visitYourRequest(YourService service) {
service. doSpecialYourProcessing(this);
}
void visitTheOtherRequest(TheOtherService service) {
throw new UnsupportedOperation("Cannot call visitTheOtherRequest in YourRequest !");
}
}
[1] actually its not the same, because now you will need to write a method for each request subtype. In 1.4, you would have to cast and do instanceof etc, to achieve what 1.5 can do with generics.
In my opinion generics would suit better here. Your interfaces pretend that a service can handle any type of Request. But in fact the implementations of each seem to be tightly coupled.
Anything implementing Service should expect to implements its methods as they are. If MyService and YourService require different method prototypes, then they are different interfaces.
Think of it from the other direction. Without knowing the implementation behind a Service interface, any caller should able to call Service.process(request) with any implementation of Request, and expect to receive a valid response.
try introducing another level of indirection:
interface Module {
Service createService();
Request createRequest();
}
class MyModule implements Module {
Service createService() { return new MyService(); }
Request createRequest() { return new MyRequest(); }
}
class YourModule implements Module {
Service createService() { return new YourService(); }
Request createRequest() { return new YourRequest(); }
}

Categories