Article JAVA Magazine 04 – 2021
Java X + 1
Velen zullen Java 17 zien als dé nieuwe release om naar over te stappen. De voornaamste reden is dat deze versie gelabeld is als ‘Long Term Support’. Dit zegt absoluut niets over de kwaliteit van de tussenliggende versies (9, 10 en 12 t/m 16). Het zegt vooral, dat op deze tussenreeks niet doorontwikkeld wordt. Kritische wijzigingen en security patches worden alleen gebackport naar LTS-versies. Als je ervoor kiest om te ontwikkelen met een niet-LTS-versie, dan dwing je jezelf eigenlijk om elk half jaar Java te upgraden of accepteer je de eventuele gevolgen om vast te houden aan deze versie.
Voor Maven is het dus van belang om dit ritme van zes maanden te kunnen volgen. Na vier jaar, sinds de introductie van Java 9, blijkt dit te lukken. Maven zelf heeft bijna geen last gehad van de verschillende versies. En hetzelfde geldt voor de meeste plugins. Eigenlijk is er maar één groep van plugins die elk half jaar structureel last heeft van de upgrade, en dat zijn degene die classes moeten kunnen lezen.
Om dit beter te begrijpen even een kort lesje over de inhoud van een class file: open een willekeurige (gecompileerde) Java class in een hex-editor, en de eerste acht bytes zien er ongeveer als volgt uit: ca fe ba be 00 00 00 3d. Hierbij zijn de eerste vier bytes altijd CAFEBABE. De volgende vier bytes zijn gereserveerd voor de versie (de eerst twee bytes voor de minor, de volgende twee bytes voor de major). Hiermee bepaalt de Java Runtime of de class te nieuw is om gebruikt te worden. In dat geval krijg je een ‘bad class file’ melding.
Er zijn een aantal plugins die classes moeten kunnen lezen. Een voorbeeld hiervan is de ‘minimize optie’ van de maven-shade-plugin. By default maakt de plugin een fat jar, waarbij de classes van je Java-project samen met alle uitgepakte dependencies in één jar worden gestopt. Met de minimize optie worden alle overbodige classes overgeslagen. Hiervoor wordt een lijst bijgehouden van alle classes die direct of indirect in je sourcecode gebruikt worden. En daarvoor moeten ook de gecompileerde classes ontleed worden. Hiervoor wordt gebruik gemaakt van ASM. En om vergelijkbare redenen is de maven-dependency-plugin afhankelijk van ASM.
Een andere techniek die afhankelijk is van ASM is ’Annotation Parsing’. Maven maakt in principe geen gebruik van Runtime Class Scanning, omdat dit in verhouding best tijdrovend is. In plaats daarvan wordt tijdens het bouwen een specifieke ‘descriptor’ aangemaakt. Zo ook voor Maven plugins. Daarvoor beschikken we over de Maven Plugin Plugin (is het niet fantastisch?!), een plugin die helpt bij het schrijven van maven plugins. Deze plugin heeft een goal genaamd ‘descriptor’, die verantwoordelijk is voor het aanmaken van de META-INF/maven/plugin.xml op basis van annotaties en Javadoc.
Dit zijn de plugins die elk half jaar gereleased zouden moeten worden, meestal met slechts een update van ASM. Gelukkig is dit niet altijd nodig. Het is met Maven mogelijk om in de pom dependencies toe te voegen aan plugins en via die weg is het ook mogelijk om ASM te upgraden.
Je zou wellicht verwachten dat ook de Maven Compiler Plugin steeds bijgewerkt moet worden, maar dat is dus niet zo. In principe hoeft deze plugin nooit classes te parsen. Alleen als je project een module descriptor bevat, dan moeten alle jars uitgelezen worden om te bepalen of dependencies op de classpath of modulepath moeten staan. Gelukkig heeft de JDK hiervoor een ModuleReader.
Mijn uiteindelijke wens is, en trouwens ook die van Java Language Architect Brian Goetz, dat Java uitgebreid wordt met een eigen ClassReader, zodat we niet steeds afhankelijk zijn van een upgrade van ASM.
In elke editie zal Robert Scholte een probleem voorleggen en deze oplossen met behulp van Apache Maven. Dit om meer inzicht te geven in Maven zelf en de vele beschikbare plugins.