Feedback on new mapping-map-to-bean feature

546 views
Skip to first unread message

Rich MacDonald

unread,
Nov 3, 2021, 12:54:09 PM11/3/21
to mapstruct-users
I just had the opportunity to try the new beta feature of mapping HashMap to an object and thought I'd share my experience. I appreciate the effort the developers are putting into this tool.

- Not relevant to the new feature, but is it possible to add a configuration to make the methods final? That would really help out the JIT.

- The general pattern is as follows:

   if ( map.containsKey( "theKey" ) ) {
       target.setValue( map.get( " theKey " )   );
   }

That causes two map operations (containsKey and get) and I don't believe the JIT will be able to resolve this to a single operation. Why not write the more efficient:

   <Type> theValue = map.get( " theKey " );
   if (theValue != null){
       target.setValue(theValue);
   }

The map code has trouble working with Map<String,Object>. So if the values are Objects, Strings, Integers, ints, etc, there seems to be no way to make it work. I get ambiguous error no matter what I try. A typical use case would be processing a json string that was deserialized to a Map<String,Object>.

Rich MacDonald

unread,
Nov 3, 2021, 1:50:56 PM11/3/21
to mapstruct-users
//Example test class
public class TestTarget {
public int myIntPrim;
public Integer myInteger;
public long myLongPrim;
public Long myLong;
public String myString;
public TestTarget otherTarget;
}

--------------------------------------------------
Following class causes the following errors:

Multiple markers at this line
- Ambiguous mapping methods found for mapping property "java.lang.Object myLong" to java.lang.Long: long mapLongPrim(java.lang.Object 
prop), java.lang.Long mapLong(java.lang.Object prop). See https://mapstruct.org/faq/#ambiguous for more info.
- Ambiguous mapping methods found for mapping property "java.lang.Object myLongPrim" to long: int mapIntPrim(java.lang.Object prop), java.
lang.Integer mapInt(java.lang.Object prop), long mapLongPrim(java.lang.Object prop), java.lang.Long mapLong(java.lang.Object prop). See https:
- Ambiguous mapping methods found for mapping property "java.lang.Object myIntPrim" to int: int mapIntPrim(java.lang.Object prop), java.lang.
Integer mapInt(java.lang.Object prop). See https://mapstruct.org/faq/#ambiguous for more info.
- Ambiguous mapping methods found for mapping property "java.lang.Object myInteger" to java.lang.Integer: int mapIntPrim(java.lang.Object 
prop), java.lang.Integer mapInt(java.lang.Object prop). See https://mapstruct.org/faq/#ambiguous for more info.

import java.util.Map;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;

@Mapper
public interface TestTargetMapper {

void test(Map<String, Object> map, @MappingTarget TestTarget target);

default int mapIntPrim(Object prop) {
return prop == null ? 0 : ((Integer) prop).intValue();
}
default Integer mapInt(Object prop) {
return prop == null ? null : (Integer) prop;
}
default long mapLongPrim(Object prop) {
return prop == null ? 0 : ((Long) prop).longValue();
}
default Long mapLong(Object prop) {
return prop == null ? null : (Long) prop;
}
default String mapString(Object prop) {
return (String) prop;
}
default TestTarget mapTarget(Object targetRef) {
// lookup reference todo
return null;
}
}

-----------------------------------------------------------
Try to remove the primitive methods:

Ambiguous mapping methods found for mapping property "java.lang.Object myLongPrim" to long: java.lang.Integer mapInt(java.lang.Object prop), java.lang.Long 
 mapLong(java.lang.Object prop). See https://mapstruct.org/faq/#ambiguous for more info.

@Mapper
public interface TestTargetMapper {

void test(Map<String, Object> map, @MappingTarget TestTarget target);

default Integer mapInt(Object prop) {
return prop == null ? null : (Integer) prop;
}
default Long mapLong(Object prop) {
return prop == null ? null : (Long) prop;
}
default String mapString(Object prop) {
return (String) prop;
}
default TestTarget mapTarget(Object targetRef) {
// lookup reference todo
return null;
}
}

-----------------------------------------------------------
Remove the offending mapInt method:

Multiple markers at this line
- Ambiguous 2step methods found, mapping Object map to int. Found conversionY( methodX ( parameter ) ): conversionY: Long-->int, method
(s)X: java.lang.Long mapLong(java.lang.Object prop); conversionY: String-->int, method(s)X: java.lang.String mapString(java.lang.Object prop); .
- Can't map property "java.lang.Object myInteger" to "java.lang.Integer myInteger". Consider to declare/implement a mapping method: "java.lang.
Integer map(java.lang.Object value)".
- Can't map property "java.lang.Object myIntPrim" to "int myIntPrim". Consider to declare/implement a mapping method: "int map(java.lang.
Object value)".
- Ambiguous 2step methods found, mapping Object map to Integer. Found conversionY( methodX ( parameter ) ): conversionY: Long-->Integer, 
method(s)X: java.lang.Long mapLong(java.lang.Object prop); conversionY: String-->Integer, method(s)X: java.lang.String mapString(java.lang.Object prop); .

@Mapper
public interface TestTargetMapper {

void test(Map<String, Object> map, @MappingTarget TestTarget target);

default Long mapLong(Object prop) {
return prop == null ? null : (Long) prop;
}
default String mapString(Object prop) {
return (String) prop;
}
default TestTarget mapTarget(Object targetRef) {
// lookup reference todo
return null;
}
}
Reply all
Reply to author
Forward
0 new messages