Возможно ли использовать классы инструментов для пакетов java.*
?Возможно ли использовать классы инструментов из java. * Package
Я хотел бы заменить тело метода java.awt.print.PrinterJob.printDialog(PrintRequestAttributeSet)
, чтобы он всегда возвращался true
.
При определении нового класса с java.*
, я получаю SecurityException: Prohibited package name: java.awt.print
. Очевидно, это происходит потому, что я пытаюсь определить класс с именем java.
в названии пакета.
Итак, есть способ обойти эту проверку безопасности или решить эту проблему по-другому?
P.S Я также попытался переопределить системное свойство java.awt.printerjob
, чтобы использовать собственную реализацию PrinterJob
. Но я потерпел неудачу, потому что мой класс не был найден. Мне не удалось найти фактический загрузчик классов PrinterJob
для загрузки моего класса.
@Test public void testInstrumentationOfJavaClasses() throws Exception
{
// replace printDialog(attrs) so that it always returns true
String typeName = "java.awt.print.PrinterJob";
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
MethodReplacer methodReplacer = new MethodReplacer(cw, "printDialog", "(Ljavax/print/attribute/PrintRequestAttributeSet;)Z");
ClassReader classReader = createClassReader(typeName);
classReader.accept(methodReplacer, ClassReader.EXPAND_FRAMES);
loadClass(cw.toByteArray(), typeName);
// the actual call of PrinterJob which as I expect to always return "true"
PrinterJob printJob = PrinterJob.getPrinterJob();
printJob.setPrintable(PRINTABLE);
PrintRequestAttributeSet printerSettings = new HashPrintRequestAttributeSet();
if (printJob.printDialog(printerSettings))
printJob.print(printerSettings);
}
public static class MethodReplacer extends ClassVisitor implements Opcodes
{
private final String methodName;
private final String methodDefenition;
public MethodReplacer(ClassVisitor classVisitor, String methodName, String methodDescr)
{
super(ASM5, classVisitor);
this.methodName = methodName;
this.methodDefenition = methodDescr;
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
{
if (methodName.equals(name) && methodDefenition.equals(desc))
{
System.out.println("visitMethod(" + name + ")");
MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, name, desc, null, new String[]{"java/awt/HeadlessException"});
mv.visitCode();
mv.visitInsn(ICONST_1);
mv.visitInsn(IRETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
return mv;
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
}
private static Class loadClass(byte[] bytecode, String typeName) throws Exception
{
ClassLoader baseClassLoader = TestPrint.class.getClassLoader();
Class<?>[] types = new Class<?>[]{String.class, byte[].class, int.class, int.class};
Method m = ClassLoader.class.getDeclaredMethod("defineClass", types);
m.setAccessible(true);
Object[] args = new Object[]{null, bytecode, 0, bytecode.length};
Class definedClass = (Class<?>) m.invoke(baseClassLoader, args);
return definedClass;
}
Спасибо за ваш ответ. Я думаю, что этот API мне поможет. Я попробую и приму ваш ответ. Или попросите какую-нибудь помощь, если что-то пойдет не так =) – nixspirit
Я зарегистрировал ClassFileTransformer и успешно переопределил PrinterJob.getPrinterJob, чтобы вернуть MyPrinterJob. Как вы сказали, я не могу использовать PrinterJob, прежде чем переопределять его в агенте, поэтому я хотел бы загрузить класс MyPrinterJob из основной библиотеки (из которой я запускаю агент). Мой код ASM вызывает Class.forName («my.print.MyPrinterJob»). NewInstance(), но java.lang.ClassNotFoundException. Возможно ли получить доступ к главному проекту ClassLoader? – nixspirit
ClassFileTransformer предоставляет доступ к загрузчику классов инструментального класса. Агент Java всегда загружается загрузчиком системного класса. –