1818import java .util .Collections ;
1919import java .util .List ;
2020import java .util .Map ;
21- import java .util .concurrent .Callable ;
2221
2322import org .hibernate .HibernateException ;
2423import org .hibernate .bytecode .enhance .internal .bytebuddy .EnhancerClassLocator ;
@@ -184,7 +183,7 @@ public ReflectionOptimizer getReflectionOptimizer(
184183 .method ( setPropertyValuesMethodName )
185184 .intercept ( new Implementation .Simple ( new SetPropertyValues ( clazz , getterNames , setters ) ) )
186185 .method ( getPropertyNamesMethodName )
187- .intercept ( MethodCall . call ( new CloningPropertyCall ( getterNames ) ) )
186+ .intercept ( new Implementation . Simple ( new GetPropertyNames ( getterNames ) ) )
188187 );
189188
190189 try {
@@ -253,7 +252,7 @@ public ReflectionOptimizer getReflectionOptimizer(
253252 .method ( setPropertyValuesMethodName )
254253 .intercept ( new Implementation .Simple ( new SetPropertyValues ( clazz , propertyNames , setters ) ) )
255254 .method ( getPropertyNamesMethodName )
256- .intercept ( MethodCall . call ( new CloningPropertyCall ( propertyNames ) ) )
255+ .intercept ( new Implementation . Simple ( new GetPropertyNames ( propertyNames ) ) )
257256 );
258257 }
259258 else {
@@ -266,7 +265,7 @@ public ReflectionOptimizer getReflectionOptimizer(
266265 .method ( setPropertyValuesMethodName )
267266 .intercept ( new Implementation .Simple ( new SetPropertyValues ( clazz , propertyNames , setters ) ) )
268267 .method ( getPropertyNamesMethodName )
269- .intercept ( MethodCall . call ( new CloningPropertyCall ( propertyNames ) ) )
268+ .intercept ( new Implementation . Simple ( new GetPropertyNames ( propertyNames ) ) )
270269 );
271270 }
272271
@@ -887,17 +886,17 @@ public Size apply(
887886 Label nextLabel = new Label ();
888887 for ( int index = 0 ; index < setters .length ; index ++ ) {
889888 final Member setterMember = setters [index ];
890- if ( enhanced && currentLabel != null ) {
889+ if ( setterMember == EMBEDDED_MEMBER ) {
890+ // The embedded property access does a no-op
891+ continue ;
892+ }
893+ if ( currentLabel != null ) {
891894 methodVisitor .visitLabel ( currentLabel );
892895 implementationContext .getFrameGeneration ().same (
893896 methodVisitor ,
894897 instrumentedMethod .getParameters ().asTypeList ()
895898 );
896899 }
897- if ( setterMember == EMBEDDED_MEMBER ) {
898- // The embedded property access does a no-op
899- continue ;
900- }
901900 // Push entity on stack
902901 methodVisitor .visitVarInsn ( Opcodes .ALOAD , 1 );
903902 methodVisitor .visitTypeInsn ( Opcodes .CHECKCAST , Type .getInternalName ( clazz ) );
@@ -1029,6 +1028,7 @@ else if ( setterMember instanceof Field ) {
10291028 }
10301029 if ( enhanced ) {
10311030 final boolean compositeTracker = CompositeTracker .class .isAssignableFrom ( type );
1031+ boolean alreadyHasFrame = false ;
10321032 // The composite owner check and setting only makes sense if
10331033 // * the value type is a composite tracker
10341034 // * a value subtype can be a composite tracker
@@ -1110,6 +1110,7 @@ else if ( setterMember instanceof Field ) {
11101110 // Clean stack after the if block
11111111 methodVisitor .visitLabel ( compositeTrackerEndLabel );
11121112 implementationContext .getFrameGeneration ().same (methodVisitor , instrumentedMethod .getParameters ().asTypeList ());
1113+ alreadyHasFrame = true ;
11131114 }
11141115 if ( persistentAttributeInterceptable ) {
11151116 // Load the owner
@@ -1174,9 +1175,20 @@ else if ( setterMember instanceof Field ) {
11741175 // Clean stack after the if block
11751176 methodVisitor .visitLabel ( instanceofEndLabel );
11761177 implementationContext .getFrameGeneration ().same (methodVisitor , instrumentedMethod .getParameters ().asTypeList ());
1178+ alreadyHasFrame = true ;
11771179 }
11781180
1179- currentLabel = nextLabel ;
1181+ if ( alreadyHasFrame ) {
1182+ // Usually, the currentLabel is visited as well generating a frame,
1183+ // but if a frame was already generated, only visit the label here,
1184+ // otherwise two frames for the same bytecode index are generated,
1185+ // which is wrong and will produce an error when the JDK ClassFile API is used
1186+ methodVisitor .visitLabel ( nextLabel );
1187+ currentLabel = null ;
1188+ }
1189+ else {
1190+ currentLabel = nextLabel ;
1191+ }
11801192 nextLabel = new Label ();
11811193 }
11821194 }
@@ -1346,17 +1358,29 @@ private static Constructor<?> findConstructor(Class<?> clazz) {
13461358 }
13471359 }
13481360
1349- public static class CloningPropertyCall implements Callable < String []> {
1361+ public static class GetPropertyNames implements ByteCodeAppender {
13501362
13511363 private final String [] propertyNames ;
13521364
1353- private CloningPropertyCall (String [] propertyNames ) {
1365+ private GetPropertyNames (String [] propertyNames ) {
13541366 this .propertyNames = propertyNames ;
13551367 }
13561368
13571369 @ Override
1358- public String [] call () {
1359- return propertyNames .clone ();
1370+ public Size apply (
1371+ MethodVisitor methodVisitor ,
1372+ Implementation .Context implementationContext ,
1373+ MethodDescription instrumentedMethod ) {
1374+ methodVisitor .visitLdcInsn ( propertyNames .length );
1375+ methodVisitor .visitTypeInsn ( Opcodes .ANEWARRAY , Type .getInternalName ( String .class ) );
1376+ for ( int i = 0 ; i < propertyNames .length ; i ++ ) {
1377+ methodVisitor .visitInsn ( Opcodes .DUP );
1378+ methodVisitor .visitLdcInsn ( i );
1379+ methodVisitor .visitLdcInsn ( propertyNames [i ] );
1380+ methodVisitor .visitInsn ( Opcodes .AASTORE );
1381+ }
1382+ methodVisitor .visitInsn ( Opcodes .ARETURN );
1383+ return new Size ( 4 , instrumentedMethod .getStackSize () + 1 );
13601384 }
13611385 }
13621386
0 commit comments