Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce getter calls during fields mapping #347

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

porunov
Copy link

@porunov porunov commented Apr 24, 2020

Partially resolves #346

This is proof of concept PR which shows that we can reduce unnecessary getter and setter calls by using variables.

This PR isn't complete and it doesn't handle primitive types. For some reason, I cannot create variables with primitive types and that is why I use primitive type wrappers (i.e. Long instead of long, Integer instead of int, etc.).

Unfortunately, I couldn't correctly resolve problems with objects which has fields with primitive type.
I have included SingleGetterCallTestCase test case shouldMapWithSingleGetterCall which shows this problem. The PR correctly works with non primitive data types and you can see that the amount of getter calls is generally decreased about 2 times (often 1 call instead of 3 calls, 2-3 calls instead of 5 calls.) It is possible to decrease those calls more (possibly to 1 call) if we add variable values to generateEqualityTestCode inside Specification but for now I just extended implementation of generateMappingCode.

That said, it is just a proof of concept. I couldn't resolve the issue with primitive data types. If anyone knows what am I doing wrong or how to correctly handle primitive types, I would love to hear that and will try to resolve the issue. As I understand, we should use unwrapped primitive types somewhere and wrapped primitive types somewhere else but I am not sure where exactly.

Also, if you someone wants to finish this optimization, feel free to take this PR and make any changes. I would really love to see this optimization to be implemented.

Stack trace:

javassist.CannotCompileException: [source error] setBooleanValue1(java.lang.Boolean) not found in ma.glasnost.orika.test.generator.SingleGetterCallTestCase$Container2
	at javassist.CtNewMethod.make(CtNewMethod.java:84)
	at javassist.CtNewMethod.make(CtNewMethod.java:50)
	at ma.glasnost.orika.impl.generator.JavassistCompilerStrategy.compileClass(JavassistCompilerStrategy.java:237)
	at ma.glasnost.orika.impl.generator.SourceCodeContext.compileClass(SourceCodeContext.java:246)
	at ma.glasnost.orika.impl.generator.SourceCodeContext.getInstance(SourceCodeContext.java:262)
	at ma.glasnost.orika.impl.generator.MapperGenerator.build(MapperGenerator.java:73)
	at ma.glasnost.orika.impl.DefaultMapperFactory.buildMapper(DefaultMapperFactory.java:1504)
	at ma.glasnost.orika.impl.DefaultMapperFactory.build(DefaultMapperFactory.java:1319)
	at ma.glasnost.orika.impl.DefaultMapperFactory.getMapperFacade(DefaultMapperFactory.java:907)
	at ma.glasnost.orika.test.generator.SingleGetterCallTestCase.shouldMapWithSingleGetterCall(SingleGetterCallTestCase.java:268)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.application.AppMainV2.main(AppMainV2.java:128)
Caused by: javassist.compiler.CompileError: setBooleanValue1(java.lang.Boolean) not found in ma.glasnost.orika.test.generator.SingleGetterCallTestCase$Container2
	at javassist.compiler.TypeChecker.atMethodCallCore(TypeChecker.java:777)
	at javassist.compiler.TypeChecker.atCallExpr(TypeChecker.java:723)
	at javassist.compiler.JvstTypeChecker.atCallExpr(JvstTypeChecker.java:170)
	at javassist.compiler.ast.CallExpr.accept(CallExpr.java:49)
	at javassist.compiler.CodeGen.doTypeCheck(CodeGen.java:266)
	at javassist.compiler.CodeGen.atStmnt(CodeGen.java:360)
	at javassist.compiler.ast.Stmnt.accept(Stmnt.java:53)
	at javassist.compiler.CodeGen.atStmnt(CodeGen.java:381)
	at javassist.compiler.ast.Stmnt.accept(Stmnt.java:53)
	at javassist.compiler.MemberCodeGen.atTryStmnt(MemberCodeGen.java:234)
	at javassist.compiler.CodeGen.atStmnt(CodeGen.java:397)
	at javassist.compiler.ast.Stmnt.accept(Stmnt.java:53)
	at javassist.compiler.CodeGen.atStmnt(CodeGen.java:381)
	at javassist.compiler.ast.Stmnt.accept(Stmnt.java:53)
	at javassist.compiler.CodeGen.atMethodBody(CodeGen.java:321)
	at javassist.compiler.CodeGen.atMethodDecl(CodeGen.java:303)
	at javassist.compiler.ast.MethodDecl.accept(MethodDecl.java:47)
	at javassist.compiler.Javac.compileMethod(Javac.java:175)
	at javassist.compiler.Javac.compile(Javac.java:102)
	at javassist.CtNewMethod.make(CtNewMethod.java:79)
	... 36 common frames omitted
20:33:03.534 [main] DEBUG m.g.o.impl.generator.MapperGenerator - Generating new mapper for (Container1, Container2)
	Orika_Container2_Container1_Mapper36939111491144$0.mapAToB(Container1, Container2) {
	 Field(arrayOfInt(int[]), arrayOfInt(int[])) : mapping to primitive array
	 Field(arrayOfString(String[]), arrayOfString(String[])) : mapping to array
	 Field(booleanValue1(boolean), booleanValue1(boolean)) : copying boolean by reference
	 Field(byteValue1(byte), byteValue1(byte)) : copying byte by reference
	 Field(charValue1(char), charValue1(char)) : copying char by reference
	 Field(doubleValue1(double), doubleValue1(double)) : copying double by reference
	 Field(enumValue(Position), enumValue(Position)) : copying Position by reference
	 Field(floatValue1(float), floatValue1(float)) : copying float by reference
	 Field(listOfString(List<String>), listOfString(List<String>)) : mapping Collection<java.lang.String> to Collection<java.lang.String>
	 Field(longValue(long), longValue(long)) : copying long by reference
	 Field(map(Map<String, Object>), map(Map<String, Object>)) : mapping from Map<String, Object> to Map<String, Object>
	 Field(key(String), key(String)) : copying String by reference
	 Field(value(Object), value(Object)) : mapping object to object
	 Field(stringValue(String), stringValue(String)) : copying String by reference
	}
	Orika_Container2_Container1_Mapper36939111491144$0.mapBToA(Container2, Container1) {
	 Field(arrayOfInt(int[]), arrayOfInt(int[])) : mapping to primitive array
	 Field(arrayOfString(String[]), arrayOfString(String[])) : mapping to array
	 Field(booleanValue1(boolean), booleanValue1(boolean)) : copying boolean by reference
	 Field(byteValue1(byte), byteValue1(byte)) : copying byte by reference
	 Field(charValue1(char), charValue1(char)) : copying char by reference
	 Field(doubleValue1(double), doubleValue1(double)) : copying double by reference
	 Field(enumValue(Position), enumValue(Position)) : copying Position by reference
	 Field(floatValue1(float), floatValue1(float)) : copying float by reference
	 Field(listOfString(List<String>), listOfString(List<String>)) : mapping Collection<java.lang.String> to Collection<java.lang.String>
	 Field(longValue(long), longValue(long)) : copying long by reference
	 Field(map(Map<String, Object>), map(Map<String, Object>)) : mapping from Map<String, Object> to Map<String, Object>
	 Field(key(String), key(String)) : copying String by reference
	 Field(value(Object), value(Object)) : mapping object to object
	 Field(stringValue(String), stringValue(String)) : copying String by reference
	}
<---- ERROR occurred here

ma.glasnost.orika.MappingException: ma.glasnost.orika.impl.generator.CompilerStrategy$SourceCodeGenerationException: Error compiling ma.glasnost.orika.generated.Orika_Container2_Container1_Mapper36939111491144$0

	at ma.glasnost.orika.impl.generator.MapperGenerator.build(MapperGenerator.java:104)
	at ma.glasnost.orika.impl.DefaultMapperFactory.buildMapper(DefaultMapperFactory.java:1504)
	at ma.glasnost.orika.impl.DefaultMapperFactory.build(DefaultMapperFactory.java:1319)
	at ma.glasnost.orika.impl.DefaultMapperFactory.getMapperFacade(DefaultMapperFactory.java:907)
	at ma.glasnost.orika.test.generator.SingleGetterCallTestCase.shouldMapWithSingleGetterCall(SingleGetterCallTestCase.java:268)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.application.AppMainV2.main(AppMainV2.java:128)
Caused by: ma.glasnost.orika.impl.generator.CompilerStrategy$SourceCodeGenerationException: Error compiling ma.glasnost.orika.generated.Orika_Container2_Container1_Mapper36939111491144$0
	at ma.glasnost.orika.impl.generator.JavassistCompilerStrategy.compileClass(JavassistCompilerStrategy.java:253)
	at ma.glasnost.orika.impl.generator.SourceCodeContext.compileClass(SourceCodeContext.java:246)
	at ma.glasnost.orika.impl.generator.SourceCodeContext.getInstance(SourceCodeContext.java:262)
	at ma.glasnost.orika.impl.generator.MapperGenerator.build(MapperGenerator.java:73)
	... 31 more
Caused by: javassist.CannotCompileException: [source error] setBooleanValue1(java.lang.Boolean) not found in ma.glasnost.orika.test.generator.SingleGetterCallTestCase$Container2
	at javassist.CtNewMethod.make(CtNewMethod.java:84)
	at javassist.CtNewMethod.make(CtNewMethod.java:50)
	at ma.glasnost.orika.impl.generator.JavassistCompilerStrategy.compileClass(JavassistCompilerStrategy.java:237)
	... 34 more
Caused by: compile error: setBooleanValue1(java.lang.Boolean) not found in ma.glasnost.orika.test.generator.SingleGetterCallTestCase$Container2
	at javassist.compiler.TypeChecker.atMethodCallCore(TypeChecker.java:777)
	at javassist.compiler.TypeChecker.atCallExpr(TypeChecker.java:723)
	at javassist.compiler.JvstTypeChecker.atCallExpr(JvstTypeChecker.java:170)
	at javassist.compiler.ast.CallExpr.accept(CallExpr.java:49)
	at javassist.compiler.CodeGen.doTypeCheck(CodeGen.java:266)
	at javassist.compiler.CodeGen.atStmnt(CodeGen.java:360)
	at javassist.compiler.ast.Stmnt.accept(Stmnt.java:53)
	at javassist.compiler.CodeGen.atStmnt(CodeGen.java:381)
	at javassist.compiler.ast.Stmnt.accept(Stmnt.java:53)
	at javassist.compiler.MemberCodeGen.atTryStmnt(MemberCodeGen.java:234)
	at javassist.compiler.CodeGen.atStmnt(CodeGen.java:397)
	at javassist.compiler.ast.Stmnt.accept(Stmnt.java:53)
	at javassist.compiler.CodeGen.atStmnt(CodeGen.java:381)
	at javassist.compiler.ast.Stmnt.accept(Stmnt.java:53)
	at javassist.compiler.CodeGen.atMethodBody(CodeGen.java:321)
	at javassist.compiler.CodeGen.atMethodDecl(CodeGen.java:303)
	at javassist.compiler.ast.MethodDecl.accept(MethodDecl.java:47)
	at javassist.compiler.Javac.compileMethod(Javac.java:175)
	at javassist.compiler.Javac.compile(Javac.java:102)
	at javassist.CtNewMethod.make(CtNewMethod.java:79)
	... 36 more

Related to orika-mapper#346

Signed-off-by: Oleksandr Porunov <alexandr.porunov@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Minimize same getter calls
1 participant