@@ -146,11 +146,9 @@ public ReflectionOptimizer getReflectionOptimizer(
146146				fastClass  = null ;
147147			}
148148			else  {
149- 				fastClass  = byteBuddyState .load ( clazz , byteBuddy  -> byteBuddy 
150- 						.with ( new  NamingStrategy .SuffixingRandom (
151- 								INSTANTIATOR_PROXY_NAMING_SUFFIX ,
152- 								new  NamingStrategy .SuffixingRandom .BaseNameResolver .ForFixedValue ( clazz .getName () )
153- 						) )
149+ 				final  String  className  = clazz .getName () + "$"  + INSTANTIATOR_PROXY_NAMING_SUFFIX ;
150+ 				fastClass  = byteBuddyState .load ( clazz , className , (byteBuddy , namingStrategy ) -> byteBuddy 
151+ 						.with ( namingStrategy  )
154152						.subclass ( ReflectionOptimizer .InstantiationOptimizer .class  )
155153						.method ( newInstanceMethodName  )
156154						.intercept ( MethodCall .construct ( constructor  ) )
@@ -210,11 +208,9 @@ public ReflectionOptimizer getReflectionOptimizer(
210208				fastClass  = null ;
211209			}
212210			else  {
213- 				fastClass  = byteBuddyState .load ( clazz , byteBuddy  -> byteBuddy 
214- 						.with ( new  NamingStrategy .SuffixingRandom (
215- 								INSTANTIATOR_PROXY_NAMING_SUFFIX ,
216- 								new  NamingStrategy .SuffixingRandom .BaseNameResolver .ForFixedValue ( clazz .getName () )
217- 						) )
211+ 				final  String  className  = clazz .getName () + "$"  + INSTANTIATOR_PROXY_NAMING_SUFFIX ;
212+ 				fastClass  = byteBuddyState .load ( clazz , className , (byteBuddy , namingStrategy ) -> byteBuddy 
213+ 						.with ( namingStrategy  )
218214						.subclass ( ReflectionOptimizer .InstantiationOptimizer .class  )
219215						.method ( newInstanceMethodName  )
220216						.intercept ( MethodCall .construct ( constructor  ) )
@@ -235,23 +231,41 @@ public ReflectionOptimizer getReflectionOptimizer(
235231			return  null ;
236232		}
237233
238- 		Class <?> superClass  = determineAccessOptimizerSuperClass ( clazz , getters , setters  );
239- 
240234		final  String [] propertyNames  = propertyAccessMap .keySet ().toArray ( new  String [0 ] );
241- 		final  Class <?> bulkAccessor  = byteBuddyState .load ( clazz , byteBuddy  -> byteBuddy 
242- 				.with ( new  NamingStrategy .SuffixingRandom (
243- 						OPTIMIZER_PROXY_NAMING_SUFFIX ,
244- 						new  NamingStrategy .SuffixingRandom .BaseNameResolver .ForFixedValue ( clazz .getName () )
245- 				) )
246- 				.subclass ( superClass  )
247- 				.implement ( ReflectionOptimizer .AccessOptimizer .class  )
248- 				.method ( getPropertyValuesMethodName  )
249- 				.intercept ( new  Implementation .Simple ( new  GetPropertyValues ( clazz , propertyNames , getters  ) ) )
250- 				.method ( setPropertyValuesMethodName  )
251- 				.intercept ( new  Implementation .Simple ( new  SetPropertyValues ( clazz , propertyNames , setters  ) ) )
252- 				.method ( getPropertyNamesMethodName  )
253- 				.intercept ( MethodCall .call ( new  CloningPropertyCall ( propertyNames  ) ) )
254- 		);
235+ 		final  Class <?> superClass  = determineAccessOptimizerSuperClass ( clazz , propertyNames , getters , setters  );
236+ 
237+ 		final  String  className  = clazz .getName () + "$"  + OPTIMIZER_PROXY_NAMING_SUFFIX  + encodeName ( propertyNames , getters , setters  );
238+ 		final  Class <?> bulkAccessor ;
239+ 		if  ( className .length () >= 0x10000  ) {
240+ 			// The JVM has a 16K limit on the class name length, so fallback to random name if the encoding exceeds that 
241+ 			bulkAccessor  = byteBuddyState .load ( clazz , byteBuddy  -> byteBuddy 
242+ 					.with ( new  NamingStrategy .SuffixingRandom (
243+ 							OPTIMIZER_PROXY_NAMING_SUFFIX ,
244+ 							new  NamingStrategy .SuffixingRandom .BaseNameResolver .ForFixedValue ( clazz .getName () )
245+ 					) )
246+ 					.subclass ( superClass  )
247+ 					.implement ( ReflectionOptimizer .AccessOptimizer .class  )
248+ 					.method ( getPropertyValuesMethodName  )
249+ 					.intercept ( new  Implementation .Simple ( new  GetPropertyValues ( clazz , propertyNames , getters  ) ) )
250+ 					.method ( setPropertyValuesMethodName  )
251+ 					.intercept ( new  Implementation .Simple ( new  SetPropertyValues ( clazz , propertyNames , setters  ) ) )
252+ 					.method ( getPropertyNamesMethodName  )
253+ 					.intercept ( MethodCall .call ( new  CloningPropertyCall ( propertyNames  ) ) )
254+ 			);
255+ 		}
256+ 		else  {
257+ 			bulkAccessor  = byteBuddyState .load ( clazz , className , (byteBuddy , namingStrategy ) -> byteBuddy 
258+ 					.with ( namingStrategy  )
259+ 					.subclass ( superClass  )
260+ 					.implement ( ReflectionOptimizer .AccessOptimizer .class  )
261+ 					.method ( getPropertyValuesMethodName  )
262+ 					.intercept ( new  Implementation .Simple ( new  GetPropertyValues ( clazz , propertyNames , getters  ) ) )
263+ 					.method ( setPropertyValuesMethodName  )
264+ 					.intercept ( new  Implementation .Simple ( new  SetPropertyValues ( clazz , propertyNames , setters  ) ) )
265+ 					.method ( getPropertyNamesMethodName  )
266+ 					.intercept ( MethodCall .call ( new  CloningPropertyCall ( propertyNames  ) ) )
267+ 			);
268+ 		}
255269
256270		try  {
257271			return  new  ReflectionOptimizerImpl (
@@ -266,6 +280,7 @@ public ReflectionOptimizer getReflectionOptimizer(
266280
267281	private  static  class  ForeignPackageClassInfo  {
268282		final  Class <?> clazz ;
283+ 		final  List <String > propertyNames  = new  ArrayList <>();
269284		final  List <Member > getters  = new  ArrayList <>();
270285		final  List <Member > setters  = new  ArrayList <>();
271286
@@ -274,7 +289,7 @@ public ForeignPackageClassInfo(Class<?> clazz) {
274289		}
275290	}
276291
277- 	private  Class <?> determineAccessOptimizerSuperClass (Class <?> clazz , Member [] getters , Member [] setters ) {
292+ 	private  Class <?> determineAccessOptimizerSuperClass (Class <?> clazz , String []  propertyNames ,  Member [] getters , Member [] setters ) {
278293		if  ( clazz .isInterface () ) {
279294			return  Object .class ;
280295		}
@@ -288,11 +303,17 @@ private Class<?> determineAccessOptimizerSuperClass(Class<?> clazz, Member[] get
288303			for  ( int  i  = 0 ; i  < getters .length ; i ++ ) {
289304				final  Member  getter  = getters [i ];
290305				final  Member  setter  = setters [i ];
306+ 				boolean  found  = false ;
291307				if  ( getter .getDeclaringClass () == foreignPackageClassInfo .clazz  && !Modifier .isPublic ( getter .getModifiers () ) ) {
292308					foreignPackageClassInfo .getters .add ( getter  );
309+ 					found  = true ;
293310				}
294311				if  ( setter .getDeclaringClass () == foreignPackageClassInfo .clazz  && !Modifier .isPublic ( setter .getModifiers () ) ) {
295312					foreignPackageClassInfo .setters .add ( setter  );
313+ 					found  = true ;
314+ 				}
315+ 				if  ( found  ) {
316+ 					foreignPackageClassInfo .propertyNames .add ( propertyNames [i ] );
296317				}
297318			}
298319			if  ( foreignPackageClassInfo .getters .isEmpty () && foreignPackageClassInfo .setters .isEmpty () ) {
@@ -304,16 +325,13 @@ private Class<?> determineAccessOptimizerSuperClass(Class<?> clazz, Member[] get
304325		for  ( int  i  = foreignPackageClassInfos .size () - 1 ; i  >= 0 ; i -- ) {
305326			final  ForeignPackageClassInfo  foreignPackageClassInfo  = foreignPackageClassInfos .get ( i  );
306327			final  Class <?> newSuperClass  = superClass ;
328+ 
329+ 			final  String  className  = foreignPackageClassInfo .clazz .getName () + "$"  + OPTIMIZER_PROXY_NAMING_SUFFIX  + encodeName ( foreignPackageClassInfo .propertyNames , foreignPackageClassInfo .getters , foreignPackageClassInfo .setters  );
307330			superClass  = byteBuddyState .load (
308331					foreignPackageClassInfo .clazz ,
309- 					byteBuddy  -> {
310- 						DynamicType .Builder <?> builder  = byteBuddy .with (
311- 								new  NamingStrategy .SuffixingRandom (
312- 										OPTIMIZER_PROXY_NAMING_SUFFIX ,
313- 										new  NamingStrategy .SuffixingRandom .BaseNameResolver .ForFixedValue (
314- 												foreignPackageClassInfo .clazz .getName () )
315- 								)
316- 						).subclass ( newSuperClass  );
332+ 					className ,
333+ 					(byteBuddy , namingStrategy ) -> {
334+ 						DynamicType .Builder <?> builder  = byteBuddy .with ( namingStrategy  ).subclass ( newSuperClass  );
317335						for  ( Member  getter  : foreignPackageClassInfo .getters  ) {
318336							final  Class <?> getterType ;
319337							if  ( getter  instanceof  Field  ) {
@@ -383,6 +401,42 @@ private Class<?> determineAccessOptimizerSuperClass(Class<?> clazz, Member[] get
383401		return  superClass ;
384402	}
385403
404+ 	private  static  String  encodeName (String [] propertyNames , Member [] getters , Member [] setters ) {
405+ 		return  encodeName ( Arrays .asList ( propertyNames  ), Arrays .asList ( getters  ), Arrays .asList ( setters  ) );
406+ 	}
407+ 
408+ 	private  static  String  encodeName (List <String > propertyNames , List <Member > getters , List <Member > setters ) {
409+ 		final  StringBuilder  sb  = new  StringBuilder ();
410+ 		for  ( int  i  = 0 ; i  < propertyNames .size (); i ++ ) {
411+ 			final  String  propertyName  = propertyNames .get ( i  );
412+ 			final  Member  getter  = getters .get ( i  );
413+ 			final  Member  setter  = setters .get ( i  );
414+ 			// Encode the two member types as 4 bit integer encoded as hex character 
415+ 			sb .append ( Integer .toHexString ( getKind ( getter  ) << 2  | getKind ( setter  ) ) );
416+ 			sb .append ( propertyName  );
417+ 		}
418+ 		return  sb .toString ();
419+ 	}
420+ 
421+ 	private  static  int  getKind (Member  member ) {
422+ 		// Encode the member type as 2 bit integer 
423+ 		if  ( member  == EMBEDDED_MEMBER  ) {
424+ 			return  0 ;
425+ 		}
426+ 		else  if  ( member  instanceof  Field  ) {
427+ 			return  1 ;
428+ 		}
429+ 		else  if  ( member  instanceof  Method  ) {
430+ 			return  2 ;
431+ 		}
432+ 		else  if  ( member  instanceof  ForeignPackageMember  ) {
433+ 			return  3 ;
434+ 		}
435+ 		else  {
436+ 			throw  new  IllegalArgumentException ( "Unknown member type: "  + member  );
437+ 		}
438+ 	}
439+ 
386440	private  static  class  ForeignPackageMember  implements  Member  {
387441
388442		private  final  Class <?> foreignPackageAccessor ;
0 commit comments