Вот загрузчик классов, который создаст фиктивный класс для каждого класса, который не найден в пути поиска, очень простым способом:
public class DummyGeneratorLoader extends URLClassLoader {
public DummyGeneratorLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
public DummyGeneratorLoader(URL[] urls) {
super(urls);
}
public DummyGeneratorLoader(
URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
super(urls, parent, factory);
}
static final byte[] template = ("Êþº¾\0\0\0002\0\n\1\7\0\1\1\0\20java/lang/Object"
+ "\7\0\3\1\0\6<init>\1\0\3()V\14\0\5\0\6\n\0\4\0\7\1\0\4Code\0\1\0\2\0\4\0"
+ "\0\0\0\0\1\0\1\0\5\0\6\0\1\0\t\0\0\0\21\0\1\0\1\0\0\0\5*·\0\b±\0\0\0\0\0\0")
.getBytes(StandardCharsets.ISO_8859_1);
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
return super.findClass(name);
}
catch(ClassNotFoundException ex) { }
return new ByteArrayOutputStream(template.length + name.length() + 10) { {
write(template, 0, 11);
try { new DataOutputStream(this).writeUTF(name.replace('.', '/')); }
catch (IOException ex) { throw new AssertionError(); }
write(template, 11, template.length - 11);
}
Class<?> toClass(String name) {
return defineClass(name, buf, 0, count); } }.toClass(name);
}
}
Однако, может быть много ожидания или структурные ограничения, накладываемые использованием кода, который не может выполнить фиктивный класс. В конце концов, прежде чем вы сможете вызвать метод интерфейса, вы должны создать экземпляр класса, чтобы он прошел проверку и успешное выполнение своего конструктора.
Если методы действительно имеют предполагаемую структуру, такую как public String name() { return "MyFoo"; }
Использование ASM может быть более простым выбором, но не для генерации произвольно сложной фальшивой среды, а для анализа этих методов и прогнозирования постоянного значения, которое они вернут. Такой метод будет состоять только из двух инструкций, ldc value
и areturn
. Вам нужно только проверить, что это так, и извлечь значение из первой инструкции.