1717
1818public final class ClassAccess {
1919
20- private static final Map <FieldAccessKey <?>, FieldAccess <?, ?>> fieldCache = new ConcurrentHashMap <>();
21- private static final Map <MethodAccessKey <?>, MethodAccess <?, ?>> methodCache = new ConcurrentHashMap <>();
20+ private static final Map <FieldAccessKey <?>, Result < FieldAccess <?, ?>, NoSuchFieldException >> fieldCache = new ConcurrentHashMap <>();
21+ private static final Map <MethodAccessKey <?>, Result < MethodAccess <?, ?>, NoSuchMethodException >> methodCache = new ConcurrentHashMap <>();
2222
2323 private ClassAccess () {}
2424
@@ -107,27 +107,7 @@ public static <S, T> FieldAccess<S, T> field(Class<S> source, String name) throw
107107
108108 private static <S , T > FieldAccess <S , T > fieldAccess (FieldAccessKey <S > key ) throws NoSuchFieldException {
109109 //noinspection unchecked
110- FieldAccess <S , T > fieldAccess = (FieldAccess <S , T >) fieldCache .get (key );
111- if (fieldAccess != null )
112- return fieldAccess ;
113-
114- synchronized (fieldCache ) {
115- //noinspection unchecked
116- fieldAccess = (FieldAccess <S , T >) fieldCache .get (key );
117- if (fieldAccess != null )
118- return fieldAccess ;
119-
120- Class <?> generated = defineHiddenIn (key .source (), generateFieldAccess (key ));
121- try {
122- //noinspection unchecked
123- fieldAccess = (FieldAccess <S , T >) generated .getDeclaredConstructor ().newInstance ();
124- fieldCache .put (key , fieldAccess );
125- } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e ) {
126- throw new RuntimeException (e ); // Should not happen
127- }
128- }
129-
130- return fieldAccess ;
110+ return (FieldAccess <S , T >) memberAccess (fieldCache , key , () -> generateFieldAccess (key ));
131111 }
132112
133113 public static <S , T > MethodAccess <S , T > method (Class <S > source , String name , Class <?>... parameters ) throws NoSuchMethodException {
@@ -136,27 +116,28 @@ public static <S, T> MethodAccess<S, T> method(Class<S> source, String name, Cla
136116
137117 private static <S , T > MethodAccess <S , T > methodAccess (MethodAccessKey <S > key ) throws NoSuchMethodException {
138118 //noinspection unchecked
139- MethodAccess <S , T > methodAccess = (MethodAccess <S , T >) methodCache .get (key );
140- if (methodAccess != null )
141- return methodAccess ;
142-
143- synchronized (methodCache ) {
144- //noinspection unchecked
145- methodAccess = (MethodAccess <S , T >) methodCache .get (key );
146- if (methodAccess != null )
147- return methodAccess ;
148-
149- Class <?> generated = defineHiddenIn (key .source (), generateMethodAccess (key ));
150- try {
151- //noinspection unchecked
152- methodAccess = (MethodAccess <S , T >) generated .getDeclaredConstructor ().newInstance ();
153- methodCache .put (key , methodAccess );
154- } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e ) {
155- throw new RuntimeException (e ); // Should not happen
156- }
157- }
119+ return (MethodAccess <S , T >) memberAccess (methodCache , key , () -> generateMethodAccess (key ));
120+ }
158121
159- return methodAccess ;
122+ private static <K extends MemberAccessKey <?>, V , E extends ReflectiveOperationException > V memberAccess (
123+ Map <K , Result <V , E >> cache ,
124+ K key ,
125+ Supplier <Result <byte [], E >> generator
126+ ) throws E {
127+ return switch (cache .computeIfAbsent (key , _ -> generator .get ()
128+ .map (bytes -> defineHiddenIn (key .source (), bytes ))
129+ .map (generated -> {
130+ try {
131+ //noinspection unchecked
132+ return (V ) generated .getDeclaredConstructor ().newInstance ();
133+ } catch (InvocationTargetException | InstantiationException | IllegalAccessException |
134+ NoSuchMethodException e ) {
135+ throw new RuntimeException (e );
136+ }
137+ }))) {
138+ case Result .Ok (V value ) -> value ;
139+ case Result .Err (E err ) -> throw err ;
140+ };
160141 }
161142
162143 private static Class <?> defineHiddenIn (Class <?> host , byte [] bytes ) {
@@ -169,12 +150,17 @@ private static Class<?> defineHiddenIn(Class<?> host, byte[] bytes) {
169150 }
170151 }
171152
172- private static byte [] generateFieldAccess (FieldAccessKey <?> key ) throws NoSuchFieldException {
153+ private static Result < byte [], NoSuchFieldException > generateFieldAccess (FieldAccessKey <?> key ) {
173154 Type objectT = Type .getType (Object .class );
174155 Type fieldAccessT = Type .getType (FieldAccess .class );
175156 Type sourceT = Type .getType (key .source ());
176157
177- Field field = key .field ();
158+ Field field ;
159+ try {
160+ field = key .field ();
161+ } catch (NoSuchFieldException e ) {
162+ return Result .err (e );
163+ }
178164 Type fieldT = Type .getType (field .getType ());
179165 Class <?> boxedField = TypeUtils .box (field .getType ());
180166 Type boxedFieldT = boxedField != null ? Type .getType (boxedField ) : fieldT ;
@@ -233,15 +219,20 @@ private static byte[] generateFieldAccess(FieldAccessKey<?> key) throws NoSuchFi
233219 ga .endMethod ();
234220
235221 cw .visitEnd ();
236- return cw .toByteArray ();
222+ return Result . ok ( cw .toByteArray () );
237223 }
238224
239- private static byte [] generateMethodAccess (MethodAccessKey <?> key ) throws NoSuchMethodException {
225+ private static Result < byte [], NoSuchMethodException > generateMethodAccess (MethodAccessKey <?> key ) {
240226 Type objectT = Type .getType (Object .class );
241227 Type methodAccessT = Type .getType (MethodAccess .class );
242228 Type sourceT = Type .getType (key .source ());
243229
244- Executable executable = key .executable ();
230+ Executable executable ;
231+ try {
232+ executable = key .executable ();
233+ } catch (NoSuchMethodException e ) {
234+ return Result .err (e );
235+ }
245236
246237 Class <?> returnType = key .constructor () ? key .source () : ((java .lang .reflect .Method ) executable ).getReturnType ();
247238 Type returnTypeT = key .constructor () ? sourceT : Type .getType (returnType );
@@ -297,7 +288,7 @@ private static byte[] generateMethodAccess(MethodAccessKey<?> key) throws NoSuch
297288 ga .endMethod ();
298289
299290 cw .visitEnd ();
300- return cw .toByteArray ();
291+ return Result . ok ( cw .toByteArray () );
301292 }
302293
303294 private static boolean isPrimitive (Type type ) {
@@ -358,15 +349,20 @@ public interface MethodAccess<S, T> {
358349 T invoke (S source , Object ... args );
359350 }
360351
361- private record FieldAccessKey <S >(Class <? extends S > source , String name ) {
352+ private interface MemberAccessKey <S > {
353+ Class <? extends S > source ();
354+ String name ();
355+ }
356+
357+ private record FieldAccessKey <S >(Class <? extends S > source , String name ) implements MemberAccessKey <S > {
362358
363359 public Field field () throws NoSuchFieldException {
364360 return source .getDeclaredField (name );
365361 }
366362
367363 }
368364
369- private record MethodAccessKey <S >(Class <? extends S > source , String name , Class <?>[] parameters ) {
365+ private record MethodAccessKey <S >(Class <? extends S > source , String name , Class <?>[] parameters ) implements MemberAccessKey < S > {
370366
371367 public boolean constructor () {
372368 return name .equals ("<init>" );
0 commit comments