Совместимость и область защиты

P4JX шифрует реализации методов защищённых классов и разрешает читать их во время выполнения только той VLX JRE, что входит в пакет. Чтобы защита была надёжной и при этом не ломала фреймворки, защищайте только основную бизнес-логику, оставляя вне области защиты точки входа фреймворка, DTO и сущности, классы, которые фреймворк создаёт или изменяет во время выполнения, и сторонние зависимости.

1. Сначала выполните сканирование совместимости

Только просканировать, ничего не создавая:

p4j javaapp app.jar --compat-scan
p4j springboot app.jar --compat-scan
p4j tomcat app.war --compat-scan

Просканировать и применить осторожные рекомендации:

p4j springboot app.jar dist --compat-apply

Параметры, заданные вами явно, всегда важнее автоматических рекомендаций. Сканирование — это статический эвристический анализ: пометка «требуется проверка» не означает, что приложение обязательно откажет, а отчёт без замечаний не заменяет регрессионное тестирование на целевой платформе.

Когда сканирование требует правки кода

Если в отчёте появляется ACTION REQUIRED, придётся менять исходный код приложения: никакой набор параметров сборки этого не решит. В отчёте указаны конкретные классы и методы, а также одна из таких рекомендаций:

  • Чтение ZIP или JAR из памяти: замените ByteArrayInputStream на файловый способ — например Files.newInputStream(Path), FileInputStream, ZipFile или JarFile.
  • Определение класса из необработанных байтов: не вызывайте ClassLoader#defineClass для защищённого класса. Используйте Class.forName() или ClassLoader.loadClass() и позвольте среде выполнения P4JX загрузить его.

После правки кода пересоберите JAR или WAR и повторите сканирование. Создавайте защищённый пакет только тогда, когда отчёт перестанет указывать на эту проблему.

2. Рекомендуемая модель защиты

публичная граница / точка входа фреймворка → обычный фасад или интерфейс → защищённая основная реализация

Например:

--protect 'com.example.service.impl.**' \
--exclude 'com.example.dto.**,com.example.config.**'

3. Классы, которые обычно не стоит защищать

  • контроллеры, сервлеты, фильтры, слушатели и классы advice;
  • классы конфигурации Spring и объекты, дополненные AOT или CGLIB;
  • DTO для Jackson, record-классы, сущности JPA и модели сериализации;
  • мосты JNI, SWT и другие нативные прослойки;
  • классы, которые переписывает или переопределяет агент, ORM, библиотека моков, средство горячей перезагрузки или собственный ClassLoader;
  • сторонние фреймворки и зависимости с открытым исходным кодом;
  • классы, которым нужно читать собственный настоящий байт-код.

4. Неподдерживаемые и ограниченные возможности JVM

Среда выполнения

  • Защищённое приложение должно работать на VLX JRE, поставляемой вместе с ним.
  • Запуск через форму -m из JPMS и запуск из одного файла исходного кода не поддерживаются.
  • Обычные JAR в пути классов должны быть зарегистрированы упаковщиком; произвольно добавлять их при развёртывании нельзя.
  • Не запускайте на VLX JRE незащищённые приложения.

Отладка и агенты

  • JVMTI, отладчики JDWP, профилировщики, средства покрытия и большинство агентов APM не поддерживаются.
  • -javaagent, -agentlib, горячая перезагрузка и переопределение классов не поддерживаются.
  • Любое внедрение в байт-код должно быть завершено до кодирования.

Оптимизация запуска

  • CDS, AppCDS и AOT не поддерживаются.
  • ZGC и Shenandoah GC выходят за рамки среды выполнения P4JX.

5. Ресурсы классов и сканеры

При чтении ресурса .class защищённого класса возвращается заготовка метаданных: имя класса, сигнатуры и аннотации сохраняются, но настоящих тел методов там нет.

  • Обычная рефлексия читает метаданные, но не восстанавливает исходный байт-код.
  • Средства, которые сами разбирают физический ZIP, по умолчанию не видят содержимое архива P4JX; попробуйте --zip-overlay scanner.
  • Сканерам пути классов вроде ClassGraph и Reflections в Spring Boot может понадобиться --layout fat.
  • Разбор архива P4JX из потока в памяти или из сети через ZipInputStream либо JarInputStream не поддерживается.
  • Представление zipfs доступно только для чтения, изменять архив через него нельзя.

6. Поведение архива

  • Суффикс .jar не делает файл обычным JAR: содержимое остаётся форматом P4JX.
  • Многоверсионные JAR при кодировании сводятся к целевой версии Java.
  • Подписи и семантика сертификатов исходного JAR не сохраняются; при необходимости подпишите итоговый результат отдельно для распространения.
  • Не изменяйте, не пересжимайте и не объединяйте созданные файлы P4JX.