404-not-find / orika

Automatically exported from code.google.com/p/orika
2 stars 0 forks source link

NPE mapping to nested property with Filter where source property is null. #162

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
What steps will reproduce the problem?

The problem is when a filter is registered with a class map containing a field 
mapping to a nested property and the source property is null.  The generated 
source calls the getter for the nested property without testing it for null.

I've attached a unit test which reproduces the problem as well as the generated 
source.

What is the expected output? What do you see instead?

I expect the A to be mapped to a B2.

What actually happens is an NPE from the generated code.

Details:

2014-05-14 12:20:40,092 DEBUG main orika.metadata.ClassMapBuilder.toClassMap: 
(ClassMapBuilder.java:683) ClassMap created:
    ClassMapBuilder.map(A, B2)
     .field( property(String), nested.property(String) )
2014-05-14 12:20:40,268 DEBUG main impl.generator.MapperGenerator.build: 
(MapperGenerator.java:81) Generating new mapper for (A, B2)
    Orika_B2_A_Mapper32011383909011$0.mapAToB(A, B2) {
     Field(property(String), nested.property(String)) : copying String by reference
    }
    Orika_B2_A_Mapper32011383909011$0.mapBToA(B2, A) {
     Field(nested.property(String), property(String)) : copying String by reference
    }
    Types used: [String]
    BoundMapperFacades used: [DefaultBoundMapperFacade<String, B1>]
    Filters used: [com.mitel.sas.shared.mapping.FilterNestedTest$1@337a60fa]
2014-05-14 12:20:40,272 DEBUG main 
orika.impl.MapperFacadeImpl.resolveMappingStrategy: (MapperFacadeImpl.java:223) 
MappingStrategy resolved and cached:
    Inputs:[ sourceClass: com.mitel.sas.shared.mapping.FilterNestedTest.A, sourceType: null, destinationType: class com.mitel.sas.shared.mapping.FilterNestedTest$B2]
    Resolved:[ strategy: InstantiateAndUseCustomMapperStrategy, sourceType: A, destinationType: B2, mapper: GeneratedMapper<A, B2> {usedConverters: [], usedMappers: [], usedMapperFacades: [DefaultBoundMapperFacade<String, B1>], usedTypes: [String] }, mapReverse?: false]
------------- ---------------- ---------------
Testcase: testAtoB(com.mitel.sas.shared.mapping.FilterNestedTest):  Caused an 
ERROR
java.lang.NullPointerException
ma.glasnost.orika.MappingException: While attempting the following mapping:
sourceClass = class com.mitel.sas.shared.mapping.FilterNestedTest$A
destinationType = com.mitel.sas.shared.mapping.FilterNestedTest.B2
resolvedStrategy = InstantiateAndUseCustomMapperStrategy<A, B2> {customMapper: 
GeneratedMapper<A, B2> {usedConverters: [], usedMappers: [], usedMapperFacades: 
[DefaultBoundMapperFacade<String, B1>], usedTypes: [String] }, unenhancer: 
ma.glasnost.orika.unenhance.BaseUnenhancer@195a404a, objectFactory: 
DefaultConstructorObjectFactory<B2>}
Error occurred: java.lang.NullPointerException
-----begin dump of current state-----------------------------
Registered object factories: 1 (approximate size: 29.2 kB)
  [B2] : {A=DefaultConstructorObjectFactory<B2>}
-------------------------------------------------------------
Registered mappers: 1 (approximate size: 1,029.1 kB)
  [0] : GeneratedMapper<A, B2> {usedConverters: [], usedMappers: [], usedMapperFacades: [DefaultBoundMapperFacade<String, B1>], usedTypes: [String] }
-------------------------------------------------------------
Registered concrete types: 5 (approximate size: 145.7 kB)
  [interface java.util.Map$Entry] : MapEntry<Object, Object>
  [interface java.util.Map] : LinkedHashMap<Object, Object>
  [interface java.util.List] : ArrayList<Object>
  [interface java.util.Set] : LinkedHashSet<Object>
  [interface java.util.Collection] : ArrayList<Object>
-------------------------------------------------------------
Resolved strategies: 1 (approximate size: 1,211.8 kB)
{source: A, dest: B2, in-place:false}: InstantiateAndUseCustomMapperStrategy<A, 
B2> {customMapper: GeneratedMapper<A, B2> {usedConverters: [], usedMappers: [], 
usedMapperFacades: [DefaultBoundMapperFacade<String, B1>], usedTypes: [String] 
}, unenhancer: ma.glasnost.orika.unenhance.BaseUnenhancer@195a404a, 
objectFactory: DefaultConstructorObjectFactory<B2>}
-------------------------------------------------------------
Unenhance strategy: ma.glasnost.orika.unenhance.BaseUnenhancer@195a404a
-----end dump of current state-------------------------------
    at ma.glasnost.orika.impl.ExceptionUtility.newMappingException(ExceptionUtility.java:55)
    at ma.glasnost.orika.impl.MapperFacadeImpl.map(MapperFacadeImpl.java:745)
    at ma.glasnost.orika.impl.MapperFacadeImpl.map(MapperFacadeImpl.java:714)
    at com.mitel.sas.shared.mapping.FilterNestedTest.testAtoB(FilterNestedTest.java:77)
Caused by: java.lang.NullPointerException
    at ma.glasnost.orika.generated.Orika_B2_A_Mapper32011383909011$0.mapAtoB(Orika_B2_A_Mapper32011383909011$0.java)
    at ma.glasnost.orika.impl.mapping.strategy.UseCustomMapperStrategy.map(UseCustomMapperStrategy.java:67)
    at ma.glasnost.orika.impl.MapperFacadeImpl.map(MapperFacadeImpl.java:735)

What version of the product are you using? On what operating system?
Version 1.4.5 on Windows 7.

Please provide any additional information below.

The issue appears to be this line in the generated source which isn't nested 
within an if null check (destination.getNested() is null):

if 
(((ma.glasnost.orika.Filter)usedFilters[0]).shouldMap(((ma.glasnost.orika.metada
ta.Type)usedTypes[0]), "property", ((java.lang.String)source.getProperty()), 
((ma.glasnost.orika.metadata.Type)usedTypes[0]), "nested.property", 
((java.lang.String)((com.mitel.sas.shared.mapping.FilterNestedTest.B1)destinatio
n.getNested()).getProperty()), mappingContext)) {

Unit Test:

import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.MappingContext;
import ma.glasnost.orika.NullFilter;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.Type;
import org.junit.BeforeClass;
import org.junit.Test;

public class FilterNestedTest {

    @BeforeClass
    public static void setUpClass() {
        System.setProperty("ma.glasnost.orika.writeSourceFiles", "true");
        System.setProperty("ma.glasnost.orika.writeSourceFilesToPath", "src");
    }

    static public class A {

        private String property;

        public String getProperty() {
            return property;
        }

        public void setProperty(String property) {
            this.property = property;
        }
    }

    static public class B1 {

        private String property;       

        public String getProperty() {
            return property;
        }

        public void setProperty(String property) {
            this.property = property;
        }
    }

    static public class B2 {

        private B1 nested;       

        public B1 getNested() {
            return nested;
        }

        public void setNested(B1 nested) {
            this.nested = nested;
        }
    }

    @Test
    public void testAtoB() {

        MapperFactory factory = new DefaultMapperFactory.Builder().build();

        factory.classMap(A.class, B2.class)
                .field("property", "nested.property")
                .register();

        factory.registerFilter(new NullFilter<Object, Object>() {
            @Override
            public <S, D> boolean shouldMap(final Type<S> sourceType, final String sourceName, final S source, final Type<D> destType, final String destName, final D dest, final MappingContext mappingContext) {
                return true;
            }
        });

        MapperFacade mapper = factory.getMapperFacade();

        mapper.map(new A(), B2.class);
    }

}

Original issue reported on code.google.com by va3...@gmail.com on 14 May 2014 at 4:54

Attachments: