Как упоминалось в других ответах, теоретически вы могли разархивировать файл rt.jar вашей JVM и заменить файл совместимой версией с исправленными ошибками.
Любые классы библиотеки классов Java, такие как классы Swing, загружаются загрузчиком классов начальной загрузки, который ищет свои классы в этом rt.jar. Как правило, вы не можете добавлять классы в этот путь к классам, не добавляя их в этот файл. Есть (нестандартный) вариант ВМ
-Xbootclasspath/jarWithPatchedClass.jar:path
где вы должны добавить файл jar, который включает исправленную версию, но это не обязательно работает на любой виртуальной машине Java. Кроме того, незаконно развертывать приложение, которое изменяет это поведение! Как указано в официальной документации:
Не развертывайте приложения, использующие этот параметр для переопределения класса в rt.jar, так как это нарушает лицензию на двоичный код Java Runtime Environment.
Однако если вы добавили класс в загрузчик классов начальной загрузки (что возможно без использования нестандартных API с помощью инструментального API), среда выполнения все равно загрузит исходный класс, поскольку в этом случае загрузчик классов начальной загрузки ищет rt .jar сначала. Поэтому невозможно «затенить» сломанный класс без изменения этого файла.
Наконец, всегда распространять ВМ с исправленным файлом, то есть ввод его в производственную систему для заказчика. В лицензионном соглашении четко указано, что вам необходимо
[...] распространять [среду выполнения Java] полностью и без изменений и только в составе ваших апплетов и приложений
Поэтому менять виртуальную машину, которую вы распространяете, не рекомендуется, так как вы можете столкнуться с юридическими последствиями, когда это будет раскрыто.
Конечно, теоретически вы можете создать свою собственную версию OpenJDK, но вы больше не сможете вызывать двоичный файл Java при его распространении, и я предполагаю, что ваш клиент не допустит этого из-за того, что вы предлагаете в ваш ответ. По опыту, многие безопасные среды вычисляют хэши двоичных файлов перед выполнением, что запрещает оба подхода к настройке работающей виртуальной машины.
Самым простым решением для вас, вероятно, будет создание агент Java, который вы добавляете в процесс виртуальной машины при запуске. В конце концов, это очень похоже на добавление библиотеки в качестве зависимости от пути к классу:
java -javaagent:bugFixAgent.jar -jar myApp.jar
Агент Java способен заменить двоичное представление класса при запуске приложения и, следовательно, может изменить реализацию ошибочного метода.
В вашем случае агент будет выглядеть примерно так, как показано ниже, где вам нужно включить исправленный файл класса в качестве ресурса:
public static class BugFixAgent {
public static void premain(String args, Instrumentation inst) {
inst.addClassFileTransformer(new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) {
if (className.equals("javax/swing/plaf/basic/BasicLabelUI")) {
return patchedClassFile; // as found in the repository
// Consider removing the transformer for future class loading
} else {
return null; // skips instrumentation for other classes
}
}
});
}
}
Пакет javadoc java.lang.instrumentation
предлагает подробное описание того, как создать и реализовать агент Java. При таком подходе вы можете использовать фиксированную версию рассматриваемого класса, не нарушая лицензионного соглашения.
По опыту, агенты Java — отличный способ исправить временные ошибки в сторонних библиотеках и в библиотеке классов Java без необходимости развертывания изменений в вашем коде или даже развертывания новой версии для клиента. По сути, это типичный вариант использования агента Java.
person
Rafael Winterhalter
schedule
10.11.2015