I'm new to modelMapper and I've encountered a problem when I tried to List of entity objects to a responseDTO.
User - Entity
UserResponseDTO - response DTO
I did the following configurating for propertyMap.
modelMapper.addMappings(new PropertyMap<List<User>, UserResponseDTO>() {
#Override
protected void configure() {
map().setName(source.get(0).getName());
map().setEmail(source.get(0).getEmail());
map().setUserRole(source.get(0).getUserRole());
map().setLanguage(source.get(0).getLanguage());
map().setTimeZone(source.get(0).getTimeZone());
// ....have more mapping ahead
}
});
But it gives following errors:
org.modelmapper.ConfigurationException: ModelMapper configuration errors:
1) Invalid source method java.util.List.get(). Ensure that method has zero parameters and does not return void.
2) Invalid source method java.util.List.get(). Ensure that method has zero parameters and does not return void.
3) Invalid source method java.util.List.get(). Ensure that method has zero parameters and does not return void.
4) Invalid source method java.util.List.get(). Ensure that method has zero parameters and does not return void.
5) Invalid source method java.util.List.get(). Ensure that method has zero parameters and does not return void.
Can anyone tell me how can I fix this issue?
It is exactly as the error message says:
Ensure that method has zero parameters
This is because (below excerpt from here)
You receive these errors because PropertyMap restricts what you can do inside configure().
I find it hard to understand what you actually are trying to map because it seems that you just want to flatten some list of Users to a DTO containing data from a just a single user, namely the first in the list (if not empty!). Maybe you are not doing what you should or maybe you do it on a wrong manner. At least it seems that you do not need any special mappings.
Assuming your User and UserResponseDTO would be like (simplified!) :
#Getter #Setter
#NoArgsConstructor
#AllArgsConstructor
public class User {
private Long id;
private String name;
private String email;
}
and
#Getter
#Setter
public class UserResponseDTO {
private String name;
private String email;
}
then mapping single user would be like:
new ModelMapper().map(users.get(0), UserResponseDTO.class);
and if you would like to map the who list, like:
new ModelMapper().map(users, UserListResponseDTO.class)
then your UserListResponseDTO would simply be something like:
#SuppressWarnings("serial")
public class UserListResponseDTO extends ArrayList<UserResponseDTO> {}
or if it happens that you need to return a list with just the first user:
new ModelMapper()..map(Arrays.asList(users.get(0)), UserListResponseDTO.class)
Related
I have a question regarding the following issue:
I'm trying to create a generic REST endpoint that will accept subclasses of a given typ.
Before working with the object, I want to confirm that it is of the type stated by the client.
The code:
Endpoint
#POST
#Path("{id}")
public Response sampleEndpoint(#PathParam("id") IdType idType, IdBaseDto<IdBaseClass> idDto) {
return idService.createItemWithId(idType, idDto);
}
Enum
public enum IdType {
FIRST(SAMPLE_ONE.class),
SECOND(SAMPLE_TWO.class),
THIRD(SAMPLE_THREE.class),
private final Class<? extends IdBaseClass> idClass;
// rest omitted
}
DTO
public class IdBaseDto<T extends IdBaseClass> {
#NotNull
private T config;
// rest omitted
}
In the createItemWithId method I want to check if the given id - respective its idClass- is of the same type as the idDto declared as IdBaseDto<IdBaseClass>.
I tried playing around with idDto.getConfig().getClass() etc., but of course this returns the IdBaseClass, declared as a type in the generic.
Question
Is there an easy - beginner friendly- way to perform a check like this given the described scenario?
I have class Response
public class Response<T extends ResponseData> {
private final T data;
//other fields, getters, setters ...
}
and the empty interface ResponseData:
public interface ResponseData {
}
It takes any object as data but this object must implement the "empty" interface which I created just to force all classes returned inside "data" element be of same super type
Now the problem is that I need to return a List inside the data element, but:
I don't find it clean to create a ResponseData implementation which serves only as a wrapper around my List
I can't return the List directly because it doesn't belong to my code and therefore I can't make it implement the marker interface (ResponseData)
So is there a solution to my problem other than the one that says I should delete the marker interface and allow any object to be returned in the data element?
n.b. : My purpose of the marker interface is to make any created classes which will be returned inside the data element inside the response,for anyone who reads them, clear towards their purpose of existence
n.b. : As mentioned in number 1 above, I know that this solution exists:
class ResponseDataWrapper implements ResponseData{
private final List<SomeType> responseList;
//getters,setters
}
but it is not clean as in this case there is a layer of nesting (i.e. the wrapper class) which is not necessary between the List and the "data" element in the response
Have a response object like this that Returns the list:
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Data
public class SomeCoolResponseForAnApi implements ResponseData{
private List<SomeObject> theListYouWantToReturn;
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Data
public static class SomeObject{
private String name;
private String age;
}
}
PS: I have used lombok, you can just use regular getters and setters.
I am building Spring Boot webflux REST API functionality that needs to work with data containing few Java type's (let's consider String, Integer, Double for example) information as part of JSON request/responses. Attribute representing Java type must be persistable inside mongodb as well (should not be problem once JSON can work with such attribute). I have following model class and type enumeration which is used by REST API to serialize/deserialize JSON message's.
#Getter
#ToString
#EqualsAndHashCode(exclude = "id")
#Document(collection = "core_scheme")
#JsonDeserialize(builder = SchemeModel.Builder.class)
#Builder(builderClassName = "Builder", toBuilder = true, setterPrefix = "with")
public class SchemeModel {
#Id
private final String id;
#Field(name = "userId") private final String userId;
#Field(name = "date") private final String creationDate;
#Field(name = "properties") private final Map<String, SchemeTypes> properties;
}
public enum SchemeTypes {
INTEGER, STRING, DOUBLE
}
Serialization and deserialization work's well. Now the problem is that when i want to resolve real Java type's stored inside Map<String, SchemeTypes> properties map i need to do mapping similar to this (just abstraction not real code):
SchemeTypes.INTEGER => Java Integer class
SchemeTypes.STRING => Java String class
SchemeTypes.DOUBLE => Java Double class
Is there any more simple way to represent Java type's stored inside model class and used within serialized/deserialized JSON file's so i can directly use it to deduce Java type without additional validation that it's valid Java type. For example if type's enumarated inside mentioned enum would have exactly same naming as real Java type's i could do following without any mapping:
public void deduceClass(SchemeTypes type) {
Class myClass = Class.forName(type.toString());
}
Note that i am looking for a solution which would work out of the box (i don't have to validate type's provided by user). If such solution would be harder to implement as mentioned mapping i will stick with mapping.
If you weren't saving this entity I could say you can actually directly map the SchemeTypes into corresponding class like following
public enum SchemeTypes {
INTEGER(Integer.class), STRING(String.class), DOUBLE(Double.class);
private final Class clazz;
private SchemeTypes(Class clazz){
this.clazz = clazz;
}
public Class getClazz(){
return clazz;
}
}
But as you are saving this it could cause some issue to deserialize.
Maybe you can save not the SchemaType instance directly but just the name of enum to overcome this like following
private final Map<String, String> properties;
and find the corresponding clazz value with a static method on this class like following
public static Class findClazzFor(String schemeTypeName){
return SchemeTypes.valueOf(schemeTypeName).getClazz();
}
Nevertheless I think cleanest solution would be keeping the SchemeType class instance mapping somewhere as a one-to-one map. And retrieve the corresponding class for provided schemeType as in the getClazz method above.
I have a class Order:
#Data
#Entity
public class Order {
private List<Project> projects;
// more fields
}
I have a two API methods in my controller:
#GetMapping
public ResponseEntity<List<Order>> getOrders() {
return ResponseEntity.ok(orderService.getOrders());
}
#GetMapping("/{id}")
public ResponseEntity<Order> getOrder(#PathVariable long id) {
return ResponseEntity.ok(orderService.getOrder(id));
}
So in this case projects is always sent via JSON, if its present its just getting serialized, if its not present its getting fetched lazily and then serialized. I could avoid it being serialized by annotating the field with #JsonIgnore. But the problem is that i want to send it sometimes and sometimes i dont. For example in getOrders() i dont want the projects to be serialized. In getOrder(...) i would want projects to be serialized. Is there any way to tell during runtime either inside custom code or by an annotation that i want to send it in one specific case and not in another case? The only thing i figured out is that - shortly before serializing - i can initialize projects with null and annotate the entity with #JsonInclude(JsonInclude.Include.NON_NULL). That way it wouldnt be sent and if i want to send it i can just avoid initializing it with null. But obviously i dont want to iterate over each Order in O(n) just to initialize its projects with null.
This is easy to achieve using "JSON Views".
First, define some classes to represent each view (e.g. internal/external):
public class OrderViews {
public static class OnlySomeFields {}
public static class AllFields extends OnlySomeFields {}
}
Next, on your class, assign a view to each field:
public class Order {
#JsonView(OrderViews.OnlySomeFields.class)
private String foo;
#JsonView(OrderViews.AllFields.class)
private String bar;
// getters/setters/etc
}
Then, in your controller, you can specify which view to use for each method:
#RestController
public class MyController {
#JsonView(OrderViews.AllFields.class)
#GetMapping("/with-all-fields")
public Order getOrderAllFields() {
return orderService.getOrder();
}
#JsonView(OrderViews.OnlySomeFields.class)
#GetMapping("/with-some-fields")
public Order getOrderAllFields() {
return orderService.getOrder();
}
}
With this setup, navigating to /with-all-fields returns a JSON containing foo and bar, while navigating to /with-some-fields returns a JSON only containing foo.
You can use this technique to selectively serialize specific fields, and should be able to apply it to your use case.
I am having one class which is having getter and setter methods i am storing that getter method in mongodb with some other collection. After getting the method name from DB how to access that method. Whether it is possible to do like this or not?
public class MappingAlgorithmScoreGenerationRules {
#Field(value = FieldNames.CATEGORY)
private String category;
#Field(value = FieldNames.ATTRIBUTE_NAME)
private MappingScoreGenerationLogic attributeName;
#Field(value = FieldNames.PRIORITY)
private Integer priority;
#Field(value = FieldNames.ATTRIBUTE_SCORE)
private Integer attributeScore;
#Field(value = FieldNames.FINAL_THRESHOLD)
private Integer finalThreshold;
#Field(value = FieldNames.RESULT_COUNT)
private Integer resultCount;
#Field(value = FieldNames.NORMALIZED_VALUE)
private Integer normalizedValue;
#Field(value = FieldNames.GETTER_METHOD)
private String getterMethod;
}
This is the class where i am storing the method name.
public class MatchEntry {
private double matchedWeight;
public double getMatchedWeight() {
return matchedWeight;
}
public void setMatchedWeight(double matchedWeight) {
this.matchedWeight = matchedWeight;
}
}
getMatchedWeight is the method name i am going to store in the DB MappingAlgorithmScoreGenerationRules.
After getting the method name how to access the method name?
I want to access like
For example: MatchEntry.(the value get from db)
Use reflection API - https://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html
Method methodToInvoke
= MatchEntry.class.getMethod("methodName", methodParams,..);
methodToInvoke.invoke(matchEntryInstance, params,..);
In Java you can achieve method access by name using reflection (https://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html).
This is a tutorial you may be able to use to lean more about this language feature: https://www.geeksforgeeks.org/reflection-in-java/
In your example, let's say you have loaded an instance of MappingAlgorithmScoreGenerationRules from the database, whose getterMethod attribute returns "getMatchedWeight".
Let's also assume that you have an instance of MatchEntry.
You would then access as follows:
MappingAlgorithmScoreGenerationRules rules = ....; //load from DB
MatchEntry entry = ...; //wherever it comes from
String getterMethodName = rules.getGetterMethod();
Method getter = MatchEntry.class.getMethod(getterMethodName);
Object value = getter.invoke(entry);
This code snippet omits Exceptions, in particular NoSuchMethodException and InvocationTargetException.
Please note that if you choose this approach, and depending heavily on the rest of your domain model, you will also need to be very careful with assumptions about the return type of the actual value (unless you can somehow guarantee that they are all the same, in which case you could cast the value).
Code that uses reflection is also inherently brittle and prone to failure as soon as you refactor. Imagine you have a populated database with these rules, and during a code review a couple of methods are renamed. Inoccuous change? Or will your entire setup break on the next deploy?
A (type-)safer approach might be to ensure all entries and related objects derive from an interface that standardises the return type on a getValue(String attributeName) method, so instead of messing with reflection you might do:
MappingAlgorithmScoreGenerationRules rules = ....; //load from DB
MatchEntry entry = ...; //wherever it comes from
String attributeName = rules.getAttribute(); //instead of 'getterMethod'
Object value = entry.getValue(attributeName);
where MatchEntry.getValue might be defined as:
public Object getValue(String attribute) {
switch(attribute) {
case "matchedWeight": return getMatchedWeight();
default: return null; //or you could throw an exception
}
}
This would easily survive any kind of method name refactoring and reorganisation, but adds the overhead of adding a case to the switch for every new attribute.
This problem could be partially solved with a runtime annotation that essentially binds an attribute name to a getter method, e.g.:
public class MatchEntry implements Matchable {
private double matchedWeight;
#MyCustomAnnotation("matchedWeight")
public double getMatchedWeight() {
return matchedWeight;
}
public void setMatchedWeight(double matchedWeight) {
this.matchedWeight = matchedWeight;
}
}
public interface Matchable {
default Object getValue(String attributeName) {
//read methods annotated with 'MyCustomAnnotation's in current class and call the one with matching value
}
}
Your getValue(String attributeName) would be tasked with reading these annotations and dynamically figuring out which getter to call. Still requires the annotation to be added everywhere it's needed, but at least it's with the getter and not hidden in some switch that's potentially duplicated across multiple class definitions.
Instead you just need a single default definition in the parent interface, as hinted above.