Skip to content

Commit 144c76e

Browse files
committed
Add Result type for handling success and error states
1 parent 276504f commit 144c76e

3 files changed

Lines changed: 292 additions & 51 deletions

File tree

foundry-core/src/main/java/org/machinemc/foundry/util/ClassAccess.java

Lines changed: 47 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717

1818
public 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

Comments
 (0)