Compatibilité et étendue de la protection

P4JX chiffre les implémentations des méthodes des classes protégées et n'en autorise la lecture, à l'exécution, qu'au VLX JRE fourni avec le paquet. Pour concilier solidité de la protection et compatibilité avec les frameworks, protégez uniquement le cœur de la logique métier et laissez de côté les points d'entrée du framework, les DTO et les entités, les classes que le framework génère ou modifie à l'exécution, ainsi que les dépendances tierces.

1. Lancez d'abord une analyse de compatibilité

Analyser sans rien produire :

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

Analyser puis appliquer les recommandations prudentes :

p4j springboot app.jar dist --compat-apply

Les options que vous indiquez explicitement l'emportent toujours sur les recommandations automatiques. L'analyse est une étude heuristique statique : une mention « vérification nécessaire » ne signifie pas que l'application échouera, et un rapport sans remarque ne remplace pas des tests de non-régression sur la plate-forme cible.

Lorsque l'analyse impose de modifier le code

Si le rapport affiche ACTION REQUIRED, il faut modifier le code source de l'application : aucune combinaison d'options d'empaquetage n'y changera rien. Le rapport nomme les classes et méthodes concernées et propose l'une de ces corrections :

  • Lecture d'un ZIP ou d'un JAR depuis la mémoire : remplacez ByteArrayInputStream par une approche fondée sur les fichiers, telle que Files.newInputStream(Path), FileInputStream, ZipFile ou JarFile.
  • Définition d'une classe à partir d'octets bruts : n'appelez pas ClassLoader#defineClass sur une classe protégée. Utilisez Class.forName() ou ClassLoader.loadClass() et laissez le runtime P4JX la charger.

Après modification du code, reconstruisez le JAR ou le WAR et relancez l'analyse. Ne produisez le paquet protégé que lorsque le rapport ne signale plus le problème.

2. Modèle de protection recommandé

frontière publique / entrée du framework → façade ou interface ordinaire → implémentation centrale protégée

Par exemple :

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

3. Classes qu'il vaut mieux laisser sans protection

  • contrôleurs, servlets, filtres, écouteurs et classes d'advice ;
  • classes de configuration Spring et objets améliorés par AOT ou CGLIB ;
  • DTO Jackson, records, entités JPA et modèles de sérialisation ;
  • classes passerelles JNI, SWT et autres interfaces natives ;
  • classes qu'un agent, un ORM, une bibliothèque de simulation, un outil de rechargement à chaud ou un ClassLoader maison réécrit ou redéfinit ;
  • frameworks tiers et dépendances open source ;
  • classes devant lire leur propre bytecode réel.

4. Fonctions JVM non prises en charge ou limitées

Environnement d'exécution

  • Une application protégée doit s'exécuter avec le VLX JRE qui l'accompagne.
  • Le démarrage par la forme -m de JPMS et le démarrage depuis un fichier source unique ne sont pas pris en charge.
  • Les JAR ordinaires du classpath doivent être enregistrés par l'empaqueteur et ne peuvent pas être ajoutés librement au déploiement.
  • N'utilisez pas le VLX JRE pour exécuter des applications non protégées.

Débogage et agents

  • JVMTI, les débogueurs JDWP, les profileurs, les outils de couverture et la plupart des agents APM ne sont pas pris en charge.
  • -javaagent, -agentlib, le rechargement à chaud et la redéfinition de classes ne sont pas pris en charge.
  • Tout tissage de bytecode doit être terminé avant l'encodage.

Optimisation du démarrage

  • CDS, AppCDS et AOT ne sont pas pris en charge.
  • ZGC et Shenandoah GC sortent du périmètre du runtime P4JX.

5. Ressources de classe et scanners

La lecture de la ressource .class d'une classe protégée renvoie une ébauche de métadonnées : le nom de la classe, les signatures et les annotations sont conservés, mais pas le corps réel des méthodes.

  • La réflexion ordinaire lit les métadonnées, mais ne restitue pas le bytecode d'origine.
  • Les outils qui analysent eux-mêmes le ZIP physique ne voient rien dans une archive P4JX par défaut ; essayez --zip-overlay scanner.
  • Les scanners de classpath comme ClassGraph et Reflections peuvent nécessiter --layout fat avec Spring Boot.
  • L'analyse d'une archive P4JX depuis un flux mémoire ou réseau avec ZipInputStream ou JarInputStream n'est pas prise en charge.
  • La vue zipfs est en lecture seule : elle ne permet pas de modifier l'archive.

6. Comportement de l'archive

  • Un suffixe .jar n'en fait pas un JAR ordinaire : le contenu reste du P4JX.
  • Les JAR multi-versions sont aplatis vers la version de Java cible pendant l'encodage.
  • Les signatures et la sémantique de certificat du JAR d'origine ne sont pas conservées ; signez séparément le livrable final si votre distribution l'exige.
  • Ne modifiez pas, ne recompressez pas et ne fusionnez pas les fichiers P4JX produits.