Use entity method as MapStruct source - java

Background
We are currently implementing an application using hexagonal architecture. Our REST API DTOs are mapped to our entities via MapStruct. This works fine. (Though, it would be much nicer if MapStruct would have support for hierarchical structures.)
Problem
However, we are facing a problem which is best described by the following example:
Consider you have an entity Person that stores the date of birth. Now, this
entity has a method which might be called int calculateAge().
The REST API's PersonDto will get an attribute int age.
Now, we want MapStruct to generate this mapping for us. Our approach was to try to configure #Mapping(target = "age", ...) to use the int calculateAge() method as source, but we did not succeed.
Believing this might be a straightforward application of MapStruct, we were quite disappointed to not come up with a clean solution after searching on this topic for hours.
Solutions
We found two solution approaches that work, but are (in our opinion) not really maintainable:
Use #Mapping(expression = "java(...)")
Use #AfterMapping to post process the constructed DTO and implement the required mappings in the annotated method
Question
Is there a cleaner way to achieve our goal, something which might look like this #Mapping(sourceMethod = "calculateAge", target = "age)?

Is there a cleaner way to achieve our goal, something which might look like this...
No, there isn't as of the MapStruct latest stable version (1.4.1.Final) of time of writing this answer. You have basically two choices which heavily depends what exactly and how you want to map the fields. I describe shortly in what case each solution is suitable for:
The first solution using expression introduces the problem the methods are hardcoded in the annotation. I prefer this solution only in the case of simple format conversions or calculations without calling a custom method (only from the existing Java API). Anyway, even with your proposed solution it would be still hardcoded. The syntax is the only thing that changes. There is effectively no difference in terms of maintainability:
#Mapping(target = "age", expression = "java(...)") // current API
#Mapping(sourceMethod = "calculateAge", target = "age") // hypothetical
Feel free to request for such feature. This solution in any case also requires imports within the mapper (#Mapper(imports = Another.class)) as well as the "hypothetical" one.
The annotation #AfterMapping is useful in case of more complex transformations and calculations. It's not as clean as a single annotation call and in fact you still write the mapping manually, however, it brings more control over the called methods which the IDE highlights before the compilation (at least you don't need an additional IDE-specific plugin). I'd go for this solution in case I need to call my custom methods and logics.

From what I've seen, Mapstruct relies on standard getters and setters. If you want to use a specific method then Mapstruct does work with #qualifiers, but I don't think the method can be in the entity. From my experience the best solution is to use #AfterMapping, as you mentioned.

Related

How to create 'update' using multiple 'set' methods

Synopsis: I'm trying to create an SQL update using jOOQ
DSL.using(connection)
.update(DSL.table("dogs"))
.set(DSL.field("age"), DSL.field("age").add(1))
.set(DSL.field("rabies"), "true")
.where(DSL.field("id").eq("Kujo"))
.execute();
Issue:
The method set(Field<Object>, Object) is ambiguous for the type UpdateSetFirstStep<Record>
Question: How do I create this update using jOOQ?
You ran into this problem: Reference is ambiguous with generics
Fixing your query
It's always a good idea to attach data types with your jOOQ expressions. In your particular case, you can work around the problem by specifying things like:
DSL.field("age", SQLDataType.INTEGER)
Or, shorter, with the usual static imports:
field("age", INTEGER)
Using the code generator
However, jOOQ is best used with its code generator, see also this article here. Not only will you avoid problems like these, but you also get compile time type safety (of data types and meta data), advanced features like implicit joins and much more.
Your query would then look like this:
DSL.using(connection)
.update(DOGS)
.set(DOGS.AGE, DOGS.AGE.add(1))
.set(DOGS.RABIES, true)
.where(DOGS.ID.eq("Kujo"))
.execute();

Access Play Framework route parameters during action composition

I have an action I want to apply to multiple routes in my Play application. These routes perform actions on a product, and a product can have various versions. I want my API to work such that the user can specify a version explicitly (via a query parameter), and if they do not specify one we will look up the latest version from the DB for them and operate on that one. So this action needs to be able to look up the latest version of a product, but we need to know which product is being asked for. In the route's controller, this is obvious. Play calls the route controller with route parameters as arguments:
#RequireProductVersion()
public CompletionStage<Result> getProduct(String productId) {
...
}
But in our action, we only have this Play internal Context object to work with. My action looks something like this:
public class RequireProductVersion extends Action<RequireProductVersion> {
#Override
public CompletionStage<Result> call(Http.Context ctx) {
final String version = ctx.request().getQueryString("version");
// if an explicit "version" parameter was specified, verify it and use it
if (version != null) {
...
} else {
// look up the latest version for this product
final String productId = ctx.request.????getParameter("productId");
return lookupLatestProductVersion(productId).thenCompose( ... );
}
}
}
Although I have some additional validity checking in that action. Sometimes I return an error from there immediately. So we could replace this action composition solution by adding the query string parameter "version" to all the routes and adding a half dozen lines of code in each of my route controllers:
#RequireProductVersion()
public CompletionStage<Result> getProduct(String productId, #Nullable String productVersion) {
final int productVersion;
try {
productVersion = Utils.getProductVersion(productId, productVersion);
} catch (ProductVersionException e) {
return CompletableFuture.completedFuture(e.getAppropriateResult());
}
...
}
But this use case is exactly what action composition should be for, I think. It just seems that the route parameters are missing. The Context object exposed in the Action call() method has a lot of stuff in it, actually. Headers are there, query parameters are there, and even the exact path being hit is there! Even if that were not so, by the point the framework has parsed the route and determined the values of the route parameters. This must be true because if it was not, then how would it know which action to call? However, it appears that these parsed parameters are completely unavailable to us. We could parse them again ourselves from the path. But why should we have to do that? We would be parsing the path twice. Why doesn't the framework expose these values?
There's an interesting article I found that, to solve a similar problem, suggests a hack that will put a url parameter into the query string parameters map.
https://alots.wordpress.com/2014/05/01/accessing-url-parameters-as-get-parameters-in-play/
However it appears to me that this method is also basically double parsing the path anyway, although I might be misinterpreting it as I'm not very familiar with Scala. If so, I might as well just hack in logic to reparse the path in my Action.
Okay so this problem is solvable in Scala. It does not appear there is currently any way to solve it in Java due to how Play Java uses annotations for action composition (and for body parsers, which is another place I ran into this exact same problem). You would have to parse the path again yourself. However, it looks like it is quite easy to accomplish in Scala. I haven’t tested either of these and I’m not very familiar with Scala, but it looks like for Play in Scala, action composition works differently.
this gist has an example of how Play Scala action composition should support this:
https://gist.github.com/wolfendale/75e8b5e9a7ace95aa7e6d123e6c6dacd
jroper’s posts in this issue thread also demonstrate what appears to me to be the same solution:
https://github.com/playframework/playframework/issues/3378#issuecomment-54925034
If those work, the technique demonstrated in the article I linked in the original post is not at all necessary to solve this problem if you are using Scala. However, because it only requires writing some code in Scala (whereas for the technique demonstrated by wolfendale and jroper, you need to write your controller in Scala as well), it could be a useful way to solve this problem and still write most of your application in Java. I don’t know for sure. I haven’t tested it and I’m not interested in that kind of hack.
You can't, at least, not out of the box. Play doesn't provide ways to get the request params in action composition.
Basically : You have to parse yourself.

Putting all returned elements into a Spring-Boot cache using annotations

Using spring-boot and its caching mechanism, is it possible to automatically store all entities returned as a collection into the cache one by one?
For instance picture the following Repository method:
#Query("...")
List<Foo> findFooByBar(Bar bar);
I'd like to insert these in a Spring Cache, one by one, meaning there would be N insertions (one for each element in the list) rather than just one (the whole list).
Example:
#Query("...")
#CachePut(value = "foos", key = "result.each.id")
List<Foo> findFooByBar(Bar bar);
Sometime ago, another person asked a similar/related question on SO and I provided an answer along with an example.
As you know, by default, out-of-the-box Spring does not handle multiple keys/values in the way that you suggested, though I like your thinking here and your example/UC is valid.
Often times, however, you can achieve what you want using an intermediate solution with just a bit of extra work. Spring is an excellent example of the Open/Closed principle and the 2 primary abstractions in Spring's Cache Abstraction is the Cache and CacheManager interfaces.
Typically, you can pick an existing implementation and "adapt" either the Cache or the CacheManager, or both, as I have done in my example.
Though not as ideal or convenient, hopefully this will give you some ideas until perhaps SPR-15213 is considered (though maybe not).
Cheers,
John

How to observe / trace class member access in Java / Scala?

I'm developing a Scala extension to an existing Java ORM (Ebean). The goal of this project is to add as much type safety as possible to the ORM.
Instead of
Ebean.find(Product.class).fetch("name", "unit").findList()
I would finally like to be able to write something like
(objects of entity[Product] with attributes name and unit) getIt
(note that this is just a very first DSL approach).
The ORM model is already defined as
#Entity
public class {
public String name;
public String unit;
}
In order to achieve type safety at compile time for the attributes in the query, I would need to access them on e.g. a dummy object like (new Product()).name.
I think this is the best way to ensure that only such model members are used that exists on that class, but, at runtime, I need a way to recognize that this variable was accessed. Otherwise I would just call that member name and wouldn't know about this in my query.
Does anybody know a way how to achieve this? Is there a possibility to trace when a variable is accessed and to give that information, at runtime, to any other object?
I already thought about hooking into getters and setters instead of using public members in the model classes, but this would either make the query or the model very ugly. Another problem is that any additional specific methods would have to be added manually for each model.
I would be happy if anyone could suggest possible solutions. Thanks!
If you are willing to define the fields of your model objects as something like the Record Fields, what Emil suggested could work, but if you're building your solution on top of a Java ORM using custom types might be an issue. If you need to track field access I think your best bet will be runtime bytecode instrumentation using a library like CGLib or Javassist. You can pass an instrumented "dummy" object into the body of your function, then track which field was accessed in a thread local. That's how it's done in Squeryl.
You could take a gander at how the Lift folks have implemented Mapper and Records. It allows for type safe queries using companion objects (as well as using raw sql). It does require inheriting traits into your model and the fields are specified as objects and not regular vals. Might be helpfull though. You can find the source for the persistance stuff here.

Dynamic Fields and/or Artificial Methods

I work with a dynamic Dataset model, which (in short) takes in attributes and stores them in a Map like this...
Dataset dataset = new Dataset();
dataset.setAttribute("name", "value");
...for later recovery, like this...
String value = dataset.getAttribute("name");
...and that has worked wonderfully for my purposes. But now I'm in a place where I'd like to use a templating engine to dynamically generate HTML. In the template, it's not ideal for me to do a lot of ${dataset.getAttribute("name")}. It would be rather nice if I could create artificial methods whenever something was added to a Dataset. For instance, if I did this...
dataset.setAttribute("name", "value");
...I'd like to be able to retrieve it like this...
String name;
name = dataset.name;
//or
name = dataset.getName();
...but so far I haven't been able to pull it off. What approach might I take here? Is it even doable?
Edit:
I understand that Velocity offers Property Lookup Rules to try to resolve dataset.name to dataset.get("name"), and that's great, but I need to know how to achieve this in the case that Velocity isn't the target as well.
See http://velocity.apache.org/engine/releases/velocity-1.5/user-guide.html#propertylookuprules
If your method was named get(String attribute) rather than getAttribute(String attribute), you could use the same syntax as for regular properties. So, either refactor your class, or add an additional get method that does the same thing as getAttribute, or transform your object into a Map, which has a get method.
In the past I have generated POJOs dynamically with Objectweb's ASM. This has the benefit that the underlying fields are type safe and much more efficient (esp for privative values)
You can use Dynamic Spring proxies with AOP technology or CGLib proxies. AOP could be used to describe getters like this : execution(public * com.bla.YourClass.get*())")
From what I've seen, it's fairly common for template engines for Java to support both
getters/setters of the form getAttribute, and
implementation of the Map interface
Before you spend too much time looking for a more generic solution (assuming the above won't be supported like it is in Velocity), it's probably worth taking a look at the other engines to see if any of them don't support it. If all your possible targets do, then you're probably fine relying on it.
I'm a big fan of making sure you actually have a problem before you spend the time to solve it.

Categories