Die neue Version 1.18.12 von Project Lombok ist veröffentlicht worden.
Typ
Beschreibung
PLATFORM
Support für JDK13 (yield in Switch Ausdrücken)
PLATFORM
Support for JDK14 (Mit pattern match instanceof Ausdrücken).
FEATURE
In der lombok.config können jetzt weitere config Dateien eingebunden werden und das sogar von .zip oder .jar Dateien.
FEATURE
Mit @Builder(setterPrefix = “set”) lässt sich das Prefix für die Setter Methoden ändern. Dieses wird aber nicht empfohlen, aber man hat die Möglcihkeit, falls es eine Library so benötigt.
FEATURE
Wenn man @Builder’s @Singular verwendet, dann wird auch ein Plural generiert.
FEATURE
Lombok kann nullity annotations eingfügen wo es relevant ist. Dei Einstellung wird in der lombok.config vorgenommen und wird auf die return value von toString, withX, chainable setX, static constructors, build, builder, usw und dem Parameter von equals, canEqual.
BUGFIX
Fix für das Sonarplugin
BUGFIX
lombok.experimental.Wither wurde in lombok.With umbenannt.
Nach 9 Monaten Entwicklungszeit steht nun die neue Version 1.12.2 der beliebten JSoup Java HTML parsing Library bereit. Es wurden Verbesserungen im Bereich der Performance vorgenommen und jede Menge Bugsfixes eingepflegt.
has kann mit relative Selektoren umgehen
keepalive funktioniert nun, wenn der Content via body() oder bodyAsBytes() geholt wird
Bulk insert von Child Node massiv beschleunigt
Und vieles mehr. Alle wichtigen Änderungen sind in der Changes Datei zu finden.
Die neue Version einbinden
Das neue Release von JSoup steht auf Meven central bereit.
Wenn man mit ./gradlew einen Build anstößt, so verwendet Gradle immer den Java Compiler den es in der Environment Variable JAVA_HOME findet. Das ist normalerweise auch ok so, aber manchmal möchte eine IDE oder im Allgeimeinen eine ältere Version verwendet, aber Quelltexte mit einer höheren Java Version übersetzen. Dann steigt Gradle aus, da der Compiler dieses nicht kompilieren kann.
Crosscompiling
Gegeben sei ein Quelltext der Java 12 voraussetzt. Dieser soll nun bei gegebener JVM OpenJDK 64-Bit GraalVM CE 19.2.0.1 übersetzt werden. Dazu muss man Gradle ein anderes Executable javac gesetzt werden. Folgender Code setzt für die Tasks AbstractCompile, Javadoc, JavaExec, Test den Javac in dem Java Home /usr/lib/jvm/java-12-openjdk.
Microstream ist die neue in Memory Datenbank für Java. Aus dem Hause XDev stammt diese revolutionäre Datenbank. Nachdem im Frühjahr das Produkt umbenannt worden ist, heißt es nicht mehr JetstreamDB sondern Microstream. Die Microstream Datenbank ist kostenlos und kann frei verwendet werden.
Was ist Microstream?
Microstream ist ein Framework das Java Objekte ultraschnell serialisieren und desialisieren des kann. Das macht sich Microstream zu nutze und umgeht damit unvermeidbare Netzwerklatenzen, die ansonsten bei klassischen RDBMs entstehen.
Wie funktioniert Microstream?
Es gibt eine Root Entität. Diese enthält alles was in der Datenbank gespeichert werden soll. Es gibt also hier kein Datenbank Schema oder ähnliches. Die Java Objekte sind die Entitäten. Das war es. Alles was sich also in dem Objektgraph unterhalb der Root Entität befindet, kann persistiert werden.
Was ist mit Queries?
Abfragen, wie man es bei einer normalen RDBMs kennt, gibt es nicht. Und braucht man auch nicht. Man verwendet einfach das Streaming API von Java und erreicht Wahnsinnig schnelle Abfragen in Millisekunden Bereich.
Demoanwendung
Es soll hier in einer kleinen Demoanwendung die Verwendung der Microstream API veranschaulicht werden. Ich verwende hier das SpringBoot Framework in der aktuellsten Version 2.1.4. Die Anwendung erzeugt bei jedem Start eine neue Einladung. Die Einladungen bestehen aus einer ID und einem Namen. Super einfach. Die ID wird hierbei immer um einen erhöht. Der Name ist hier statisch. Um den Code vom unnötigen Boilerplate frei zu halten, verwende ich Lombok.
Abhängigkeiten einbinden
Es muss das Repository von microstream eingebunden werden. Die Group ID .heißt one.microstream und es muss das Artefakt storage.embedded in der Version 01.00.00-MS-RC1 Hier das Gradle Buildscript:
Die Invocartion stellt die Entität des Repositories dar. Sie besteht aus der ID und dem Namen der Einladung.
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Invocation {
private Long id;
private String name;
}
Pretty simple, aber erfüllt für die Demo genau seinen zweck.
Insert new Invocation
Der CommandLineRunner wird beim Starten des SpringBoot Container ausgeführt. Es sind für die Verwendung der in Memory Datenbank zwei statische Variable nötig. Die eine enthält das Root des Objektgraphen hier ROOT genannt und eine STORAGE die für das Persistieren auf der Festplatte.
Wie gelange jetzt die Daten in den Objektgraphen?
@Component
@Log
public class InitDatabase implements CommandLineRunner {
// to stop spring boot application
@Autowired
private ConfigurableApplicationContext cac;
// this is the ROOT of object graph
private static Reference<InvocationRepository>ROOT =
X.Reference(new InvocationRepository());
// Storage manager
private static EmbeddedStorageManager STORAGE =
EmbeddedStorage.start(ROOT);
@Override
public void run(String... args) throws Exception {
// load all into a local list
var rootData = ROOT.get();
List<Invocation> invocations = rootData.getInvocations();
// print size of Repository
log.info("size: " + rootData.size());
// add a new Incocation to Repository
Invocation invocation = new Invocation();
invocation.setId(Long.valueOf(rootData.size()+1));
invocation.setName("Test");
invocations.add(invocation);
invocations.forEach(i-> log.info(i.toString()));
// store
STORAGE.store(ROOT.get().getInvocations());
// close
STORAGE.shutdown();
// shutdown SpringBoot container
cac.close();
}
}
Das Repository
Das Repository ist sehr einfach gehalten.
public class InvocationRepository {
private final List<Invocation> invocations = new ArrayList<>();
/**
* get a List of Invocations
* @return List of Invocation
*/
public List<Invocation> getInvocations() {
return invocations;
}
/**
* Size of Repository
* @return
*/
public int size() {
return invocations.size();
}
}
Einschränkungen
Leider gibt es mit dem Classloader ein Problem, wenn man die DevTools von SpringBoot mit einbindet. Daher habe ich diese aktuell noch nicht eingebunden.
Am 12.02.2019 ist die Neue Version von Lombok erschienen. Neben einigen Bugfixes enthält das Update initialen Support für die EA von JDK 12 und weiteren neuen Features wie zum Beispiel die Generierung von Javadocs.
Die wichtigsten Änderungen im Einzelnen
FEATURE: Javadoc an Feldern werden nun auch an den Builders Setter Methoden kopiert.
FEATURE: Es gibt jetzt einen Konfigurationseinstellung um das Verhalten von toString() die den super() Konstruktor aufruft zu beeinflussen
ENHANCEMENT: Verbesserte Konsolenausgabe wenn toString auf Enums angewandt wird. Es wird nun der Name der Konstanten ausgegeben
Unterstütung für JDK12. Aufgrund von Änderungen an Switchstatements gab es Probleme mit Lombok
BUGFIX: @Delegate in Zusammenhang mit @NonNull Annotation verursacht nun unter JDK8 keinen Fehler mehr
BUGFIX: Delombok funktionierte seit der Version 1.18.4 nicht korrekt, weil ein NoClassDefFoundError Fehler ausgegeben worden ist
Die aktuelle Version von Lombok.jar befindet sich wie immer im Downloadbereich von dem Projekt.
Häufig hat man eine Liste von Werten in einem String die durch Komma getrennt sind. Diese Wertelisten möchte man natürlich in einer Liste weiterverarbeiten. Die Methode .split() dient dazu, aber man erhält ein Array von Strings und das lässt sich nicht so schön verwenden.
Lösung
Die Klasse Stream bietet mit der Methode .of() uns eine Möglichkeit dieses Array in einen Stream zu wandeln. Dieses mappen wir in neue String Objekte und verwandeln es mit der finalen Methode collect mit dem statischen Collectors.toList() Argument in eine Liste.
public static List<String> split(String string){
return Stream.of(string.split(","))
.map (element -> new String(element))
.collect(Collectors.toList());
}
Die GraalVM ist eine neuartige Virtuelle Maschine die hochoptimierten Code erzeugen kann. Die VM ist Polyglot, das heißt sie ist nicht auf eine Programmiersprache begrenzt und auch nicht auf ein Zielsystem festgelegt. Es lassen sich JavaScript Programme für Oracle Datenbank kompilieren und es ist auch schon MySQL in Planung.
Die Version 1.0.0 ist kurz vor dem Release und es ist Release Candidate 9 aktuell. Da GraalVM völlig OpenSource ist, ist auch jeder der interesse an dem Projekt hat, aufgerufen das auszuprobieren und Fehler und Verbesesserungsvorschläge zu melden.
In diesem Betrag stelle ich kurz einige der Möglichkeiten von GraalVM vor. Ich beleuchte Polyglotte Programmierung und das Kompilieren in native Code. Auf Details zur Implementierung der VM und andere technische Hintergründe gehe ich in diesem Beitrag nicht ein.
Installation
Wie immer hier die nötigen Pakete die unter Manjaro/Arch Linux zu installieren sind.
$ sudo archlinux-java status
Available Java environments:
java-10-openjdk
java-11-openjdk
java-8-graal
java-8-openjdk (default)
Es muss noch die Default VM geändert werden.
sudo archlinux-java set java-8-graal
Nun sollte auch das Graal Component Updater (gu) im Pfad vorhanden sein.
$ gu
GraalVM Component Updater v1.0.0
Usage:
gu info [-cFlprstuv] <param> prints info about specific component (from file, URL or catalog)
gu available [-lv] <expr> lists components available in catalog
gu install [-0cfFnorvyxY] <param> installs a component package
gu list [-clv] <expression> lists installed components, or components from catalog
gu uninstall [-0fxv] <id> uninstalls a component
gu rebuild-images rebuilds native images. Use -h for detailed usage
Common options:
...
Mit dem Graal Updater lassen sich Komponenten nachinstallieren und updaten. Da wir für die Installation den Paketmanager Pacman verwendet haben und die Installation im Systemverzeichnis liegt, schlägt ein Update oder eine Installation fehl.
Polyglottes Beispiel
Auf der Homepage von Graal gibt es ein paar Beispiele. Ein Beispiel was mich am meisten fasziniert, ist das Beispiel wo die Anwendung der Polyglotten Programmierung gezeigt wird.
Vorbereitung
Zunächst müssen die Quelltexte ausgecheckt werden. Dazu wird die übliche Prozedur mit GIT clone verwedendet. Danach rufen wir das Buildskript auf, dass per NPM die benötigten Dependencies installiert.
git clone https://github.com/graalvm/graalvm-demos
cd graalvm-demos/polyglot-javascript-java-r
./build.sh
Quelltext des Servers
Die server.js ist sehr kurz und daher zeige ich hier den gesamten Quelltext des Servers.
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
*
* Subject to the condition set forth below, permission is hereby granted to any
* person obtaining a copy of this software, associated documentation and/or
* data (collectively the "Software"), free of charge and under any and all
* copyright rights in the Software, and any and all patent rights owned or
* freely licensable by each licensor hereunder covering either (i) the
* unmodified Software as contributed to or provided by such licensor, or (ii)
* the Larger Works (as defined below), to deal in both
*
* (a) the Software, and
*
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
* one is included with the Software each a "Larger Work" to which the Software
* is contributed by such licensors),
*
* without restriction, including without limitation the rights to copy, create
* derivative works of, display, perform, and distribute the Software and make,
* use, sell, offer for sale, import, export, have made, and have sold the
* Software and the Larger Work(s), and to sublicense the foregoing rights on
* either these or other terms.
*
* This license is subject to the following condition:
*
* The above copyright notice and either this complete permission notice or at a
* minimum a reference to the UPL must be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
const express = require('express')
const app = express()
const BigInteger = Java.type('java.math.BigInteger')
app.get('/', function (req, res) {
var text = 'Hello World from Graal.js!<br> '
// Using Java standard library classes
text += BigInteger.valueOf(10).pow(100)
.add(BigInteger.valueOf(43)).toString() + '<br>'
// Using R methods to return arrays
text += Polyglot.eval('R',
'ifelse(1 > 2, "no", paste(1:42, c="|"))') + '<br>'
// Using R interoperability to create graphs
text += Polyglot.eval('R',
`svg();
require(lattice);
x <- 1:100
y <- sin(x/10)
z <- cos(x^1.3/(runif(1)*5+10))
print(cloud(x~y*z, main="cloud plot"))
grDevices:::svg.off()
`);
res.send(text)
})
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
Was heißt Polyglotte Programmierung?
Wenn man den Quelltext des Server sich anschaut, dann erkennt man das Polyglot.eval() aufgerufen wird. Mit .eval können Ausdrücke von anderen Sprachen (hier R) evaluiert werden und das Ergebnis kann normal weiterverarbeitet werden. Auch der Zugriff auf Java Klassen funktioniert, ohne eine spezielle Anweisung.
Starten des NodeJS Server
Der Server der mitgelieferten NodeJS Version in dem graal-bin Package gestartet. Der Parameter –polyglot ermöglicht das die Polyglotte Ausführung möglich wird. Der Parameter –jvm sorgt dafür, dass GraalVM zum Zuge kommt und die Optimierungen durchgeführt werden.
Die Anwendung läßt sich im Chrome Devtools Debugger debuggen. Man muss den Server nur mit dem Parameter –inspect starten.
$ /usr/lib/jvm/java-8-graal/jre/bin/node --inspect --polyglot --jvm server.js
Debugger listening on port 9229.
To start debugging, open the following URL in Chrome:
chrome-devtools://devtools/bundled/js_app.html?ws=127.0.0.1:9229/ea4a92b-3aa8163241f
Nun sehen wir in der Konsole die URL mit der man die Anwendung debuggen kann.
Hinweis: Aktuell kennt KDE das Custom Protocol nicht, so dass die URL aus der Konsole heraus nicht direkt geöffnet werden kann. Es läßt sich bestimmt ein Protocol Handler registieren, so dass die URI direkt geöffnet werden kann.
Jetzt muss man nur den Ordner mit den Quelltexten in den Workspace ziehen und kann dann den Quelltext des server.js öffnen und zum Beispiel einen Breakpoint setzen und Variablen inspizieren.
Nativer Code
Die GraalVM kann aus einer JavaVM und einem JAR-File ein Blob erzeugen, der sich genauso verhält wie eine Anwendung die in einer “normalen” Java VM läuft. Die Startupzeiten sind dann extrem gering, im Vergleich zu den Startupzeiten einer HotSpot VM. Dieses macht Java Anwendungen noch interessanter in Containern, wo schnell eine neue Instanz einer Anwendung gespawnt werden muss.
Hierfür ist ein Sub Projekt der GraalVM zuständig. Es nennt sich SubstrateVM. JVM Ökosystem muss noch an GraalVM angepasst werden. Für Spring ist mit der Version 5.1 initialer Support für die neue VM vorhanden.
Übersetzen eines JAR
Für die Übersetzung wird in der GraalVM ein Programm native-image mitgeliefert, welches eine JAR untersucht und dann ein Blob erzeugen kann. Der Blob kann dann agnz normal ausgeführt werden.
native-image -jar /Pfad/zum/JAR
Limitierungen
Die SubstrateVM befindet sich noch in der aktiven Entwicklung und daher werden noch nicht alle Funktionen vollständig unterstützt (siehe hier).
In nativen Code übersetzen
Das bauen von nativen Anwendungen mit native-image funktioniert mit Spring Boot Anwendungen noch nicht, weil das dynamische laden von Klassen wohl (noch) nicht voll umfänglich unterstützt wird.
Hier die Fehlermeldung, wenn versucht ein Spring Boot Application zu übersetzen.
$ native-image -jar ./build/libs/spring-data-jdbc-demo-0.0.1-SNAPSHOT.jar
Build on Server(pid: 8784, port: 42925)
[spring-data-jdbc-demo-0.0.1-SNAPSHOT:8784] classlist: 334.59 ms
[spring-data-jdbc-demo-0.0.1-SNAPSHOT:8784] (cap): 3,266.94 ms
[spring-data-jdbc-demo-0.0.1-SNAPSHOT:8784] setup: 3,846.85 ms
[spring-data-jdbc-demo-0.0.1-SNAPSHOT:8784] analysis: 4,875.69 ms
error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Unsupported field java.net.URL.handlers is reachable
To diagnose the issue, you can add the option --report-unsupported-elements-at-runtime. The unsupported element is then reported at run time when it is accessed the first time.
Detailed message:
Error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Unsupported field java.net.URL.handlers is reachable
To diagnose the issue, you can add the option --report-unsupported-elements-at-runtime. The unsupported element is then reported at run time when it is accessed the first time.
Trace:
at parsing java.net.URL.setURLStreamHandlerFactory(URL.java:1118)
Call path from entry point to java.net.URL.setURLStreamHandlerFactory(URLStreamHandlerFactory):
at java.net.URL.setURLStreamHandlerFactory(URL.java:1110)
at org.springframework.boot.loader.jar.JarFile.resetCachedUrlHandlers(JarFile.java:401)
at org.springframework.boot.loader.jar.JarFile.registerUrlProtocolHandler(JarFile.java:391)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:48)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
at com.oracle.svm.core.JavaMainWrapper.run(JavaMainWrapper.java:164)
at com.oracle.svm.core.code.CEntryPointCallStubs.com_002eoracle_002esvm_002ecore_002eJavaMainWrapper_002erun_0028int_002corg_002egraalvm_002enativeimage_002ec_002etype_002eCCharPointerPointer_0029(generated:0)
Error: Processing image build request failed
Am 30.10.2018 ist die neue Version 1.18.4 von Lombok erschienen. Wie immer sind einige Bugs in Zusammenhang mit Java Versionen größer 9 behoben worden. Es sind aber auch inkompatible Änderungen vorgenommen worden. Das Jar kann von hier runtergeladen werden.
Lombok unterstützt nun Eclipse Photon. Der lombok.patcher verwendete OpCodes.ASM4, welches nun nicht mehr von Eclipse verwendet wird. Eclipse verwendet nun invoke dynamic.
Inkompatible Änderungen
FieldNameConstants wurden aufgrund eines Tickets neu redesigned. Das Feature bleibt weiterhin als experimentel gekennzeichnet, da noch nicht klar ist, ob es wirklich eine Verbesserung der Lesbarkeit mit sich bringt. Dokumentation FieldNameConstants.
Lombok kopiert nun immer bestimmte Annotationen, damit das Verhalten nicht verloren geht. Z.B. @NonNull.