Details siehe https://spring.io/blog/2019/07/04/explore-the-project-on-start-spring-io
Allgemein
JBoss EAP 7.2 mit Java EE 8-Untertützung freigegeben
Details bei Red Hat unter https://www.redhat.com/en/blog/announcing-general-availability-red-hat-jboss-enterprise-application-platform-72
Stichwörter:
- greater compliance with Java Enterprise Edition (EE) 8
- JBoss EAP 7.2 is Java EE 8 certified
- Java EE 8 certification introduces new capabilities designed to improve portability and security of applications and the manipulation of JSON documents
- enhancements related to the support of HTTP/2
- JBoss EAP 7.2 also supports OpenJDK 11, Oracle JDK 11, Java SE 11
- Red Hat offers supportfor OpenJDK 8 until 2023 and OpenJDK 11 until 2024.
- Eclipse MicroProfile Config, a microservices library to manage application configurable parameters across environments
- Eclipse MicroProfile REST Client, a microservices library designed to more easily invoke microservices in a type-safe manner
- Eclipse MicroProfile OpenTracing, a microservices library to trace microservices-based applications
- Eclipse MicroProfile Health, a microservices library to check the state of microservices-based applications
- tighter integration with Red Hat OpenShift for clustered applications
Amazon Corretto 8 verfügbar
Mein Open-Source-Projekt PPTX Folien in Asciidoc konvertieren
Offene Java/JavaScript-Seminare in 2018
22.–26. Oktober 2018 (KW 43), 12.–16. November 2018 (KW 46)
Java für Fortgeschrittene (›JAVA2‹)
8.–12. Oktober 2018 (KW 41), 26.–30. November 2018 (KW 48)
15.–17. Oktober 2018 (KW 42), 5.–7. November 2018 (KW 45), 3.–5. Dezember 2018 (KW 49)
JavaScript für Web-Entwickler (›JAVASCRIPT‹)
15.–17. Oktober 2018 (KW 42), 5.–7. November 2018 (KW 45), 3.–5. Dezember 2018 (KW 49)
Eigene Doclets programmatisch ausführen – was ist neu in Java 10?
Das javadoc-Tool hat die Aufgabe, den Java-Quellcode auszulesen und die Javadoc-Kommentare zu extrahieren. Was dann mit den Daten passiert, ist die Aufgabe eines Doclets. Das Standard-Doclet von Oracle erzeugt die bekannte Struktur auf verlinkten HTML-Dateien, aber es lassen sich auch eigene Doclets schreiben, um etwa in Javadoc-Kommentaren enthaltene Links auf Erreichbarkeit zu prüfen oder UML-Diagramme aus den Typbeziehungen zu erzeugen. Hervorzuheben ist JDiff (http://javadiff.sourceforge.net/), was Differenzen in unterschiedlichen Versionen der Java-Dokumentation – wie neu hinzugefügte Methoden – erkennt und meldet.
Die Doclet-API ist Teil vom JDK, und deklariert Typen und Methoden, mit denen sich Module, Pakete, Klassen, Methoden usw. und deren Javadoc-Texte erfragen lassen. Allerdings gibt es zwei Doclet-APIs:
- Im Paket javadoc.doclet (Modul jdk.javadoc) ist die aktuelle API.
- Im Paket sun.javadoc ist die mittlerweile deprecated API, allerdings einfacher zu nutzen.
Beispiel
Im folgenden Beispiel wollen wir ein kleines Doclet schreiben, das Klassen, Attribute, Methoden und Konstruktoren ausgibt, die das Javadoc-Tag @since 10 tragen. So lässt sich leicht ermitteln, was in der Version Java 10 alles hinzugekommen ist. Doclets werden normalerweise von der Kommandozeile aufgerufen und dem javadoc-Tool übergeben, doch da es mit der Tool-Schnittstelle auch selbst geht, können wir ein Programm mit main(…)-Methode schreiben, das die Neuerungen auf der Konsole ausgibt.
package com.tutego.insel.tools; import java.io.IOException; import java.nio.file.*; import java.util.Arrays; import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; import javax.tools.*; import com.sun.javadoc.*; @SuppressWarnings( "deprecation" ) public class FindSinceTagsInJavadoc { public static class TestDoclet { public static boolean start( RootDoc root ) { Arrays.stream( root.classes() ).forEach( TestDoclet::processClass ); return true; } private static void processClass( ClassDoc clazz ) { Predicate<Doc> hasSinceTag = doc -> Arrays.stream( doc.tags( "since" ) ) .map( Tag::text ).anyMatch( "10"::equals ); if ( hasSinceTag.test( clazz ) ) System.out.printf( "%s -- Neuer Typ%n", clazz ); Arrays.stream( clazz.fields() ).filter( hasSinceTag ) .forEach( f -> System.out.printf( "%s -- Neues Attribut%n", f ) ); Arrays.stream( clazz.methods() ).filter( hasSinceTag ) .forEach( m -> System.out.printf( "%s -- Neue Methode%n", m ) ); Arrays.stream( clazz.constructors() ).filter( hasSinceTag ) .forEach( c -> System.out.printf( "%s -- Neuer Konstruktor%n", c ) ); } } public static void main( String[] args ) throws IOException { Path zipfile = Paths.get( System.getProperty( "java.home" ), "lib/src.zip" ); try ( FileSystem srcFs = FileSystems.newFileSystem( zipfile, null ) ) { Predicate<Path> filesToIgnore = p -> p.toString().endsWith( ".java" ) && ! p.toString().startsWith( "/javafx" ) && ! p.toString().startsWith( "/jdk" ) && ! p.toString().endsWith( "module-info.java" ) && ! p.toString().endsWith( "package-info.java" ); List<Path> paths = Files.walk( srcFs.getPath( "/" ) ) .filter( filesToIgnore ).collect( Collectors.toList() ); DocumentationTool tool = ToolProvider.getSystemDocumentationTool(); try ( StandardJavaFileManager fm = tool.getStandardFileManager( null, null, null ) ) { Iterable<? extends JavaFileObject> files = fm.getJavaFileObjectsFromPaths( paths ); tool.getTask( null, fm, null, TestDoclet.class, List.of( "-quiet" ), files ).call(); } } } }
Unsere main(…)-Methode bindet zunächst das ZIP-Archiv vom JDK mit den Quellen als Dateisystem ein. Im nächsten Schritt durchsuchen wir das Dateisystem nach den passenden Quellcodedateien und sammeln sie in eine Liste von Pfaden. Jetzt kann das DocumentationTool mit unserem Doclet konfiguriert und aufgerufen werden. call() startet das Parsen aller Quellen und führt anschließend zum Aufruf von start(RootDoc) unseres Doclets.
In unserer start(…)-Methode laufen wir über alle ermittelten Typen und rufen dann processClass(ClassDoc) auf. Dort passiert der eigentliche Test. Die Metadaten kommen dabei über diverse XXXDoc-Typen. Ein Predicate zieht den Tag-Test heraus.
Spring Tool Suite 3.9.5 erschienen
Kurz nach Eclipse Photon basiert nun auch die STS auf der aktuellsten Eclipse-Version:
Autor für MySQL-Administrationshandbuch gesucht
Der www.rheinwerk-verlag.de ist auf der Suche nach einem Überarbeiter für das Administrationshandbuch zu MySQL (https://www.rheinwerk-verlag.
nicht mehr die Zeit. Interessierte Autoren mögen sich bitte unter melden bei:
Christoph Meister, Lektor Computing
Rheinwerk Verlag GmbH | Rheinwerkallee 4 | 53227 Bonn
Telefon +49 228 42150-45
christoph . meister @ rheinwerk –
Nacktes Thymeleaf
Oftmals nutzen die Beispiele im Internet Spring, oder — noch spezieller — Thymeleaf wird als Template-Engine in Spring MVC eingesetzt, daher jetzt nackt, so einfach es geht.
In unsere POM kommt:
<!-- https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf --> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf</artifactId> <version>3.0.9.RELEASE</version> </dependency>
Wir schreiben das Template demo.html:
<!DOCTYPE html> <html> <body> <p>Hey <span data-th-text="${name}">CHRISTIAN</span></p> </body> </html>
Und dann kann ein Java-Programm name füllen:
import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; import org.thymeleaf.templateresolver.FileTemplateResolver; public class ThymeleafDemo { public static void main( String[] args ) { FileTemplateResolver resolver = new FileTemplateResolver(); resolver.setCharacterEncoding( "UTF-8" ); TemplateEngine templateEngine = new TemplateEngine(); templateEngine.setTemplateResolver( resolver ); Context ctx = new Context(); ctx.setVariable( "name", "tutego" ); String result = templateEngine.process( "demo.html", ctx ); System.out.println( result ); } }
Aktuelle offene Java-Seminare Q2/Q3 2018
22.–24. Mai 2018 (KW 21), 11.–13. Juni 2018 (KW 24), 16.–18. Juli (KW 29)
14.–18. Mai 2018 (KW 20), 25.–29. Juni 2018 (KW 26), 6.–10. August 2018 (KW 32), 17.–21. September 2018 (KW 38), 5.–9. November 2018 (KW 45)
Java für Fortgeschrittene (›JAVA2‹)
28. Mai bis 1. Juni 2018 (KW 22), 9.–13. Juni 2018 (KW 28), 20.–24. August 2018 (KW 34), 8.–12. Oktober 2018 (KW 41), 26.–30. November 2018 (KW 48)
23.–27. April 2018 (KW 17), 11.–15. Juni 2018 (KW 24), 23.–27. Juli 2018 (KW 30), 3.–7. September 2018 (KW 36), 22.–26. Oktober 2018 (KW 43)
Nebenläufige Programmierung mit Threads (›JAVACON‹)
7.–8. Mai (KW 19), 14.–15. Juni (KW 24), 19.–20. Juli (KW 29)
Gradle 4.6 ist fertig
Details unter https://docs.gradle.org/4.6/release-notes.html
WildFly 12 ist nun final
Infos unter http://wildfly.org/news/2018/02/28/WildFly12-Final-Released/. Wie auch Java 10 gibt es zeitbasierte Releasese: http://lists.jboss.org/pipermail/wildfly-dev/2017-December/006250.html.
NetBeans 9 Beta ist auf dem Weg
Infos darüber unter https://netbeans.apache.org/download/nb90/index.html.
Allerdings frage ich mich, wer NB noch verwendet, ihr? Ich halte den NB-Zug für abgefahren. In den Insel kommen die Anmerkungen zu NB raus und IntelliJ stattdessen rein.
Die 9er Version kann kein Java 10, und die Entwickler freuen sich über Java 9-Support, wow, 1/2 Jahr nach dem Java 9 Release. In 2 Wochen kommt Java 10.
Bald neue JDBC-Async-Bibliothek im Paket java.sql2?
Präsentation und Code verlinkt unter https://blogs.oracle.com/java/jdbc-next%3a-a-new-asynchronous-api-for-connecting-to-a-database
Sehr spannend!
Spring Boot 2.0 freigegeben
Siehe https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Release-Notes und https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Migration-Guide.
Es knarrzt an einigen Stellen, ich musste zum Beispiel meine CRUD-Implementierungen anpassen, die Methodennamen haben sich geändert. Wie sind eure Erfahrungen?
Iterator vom Stream besorgen
Sich einen Iterator von einem Stream geben zu lassen ist nützlich, weil dann der Zeitpunkt des Konsumierens vom Zeitpunkt des Stream-Aufbaus getrennt werden kann. Es ist nicht einfach mehrere Streams gleichzeitig abzulaufen, doch mit Iteratoren funktioniert das. Zudem lässt sich in Stream mit einer Generator-Funktion einfach aufbauen, in Iterator aber nicht.
Beispiel: Aus zwei Streams sollen jeweils alterrnierend das nächste Element konsumiert und ausgegeben werden.
Iterator<Integer> iterator1 = Stream.of( 1, 3, 5 ).iterator(); Iterator<Integer> iterator2 = Stream.of( 2, 4, 6, 7, 8 ).iterator(); while ( iterator1.hasNext() || iterator2.hasNext() ) { if ( iterator1.hasNext() ) System.out.println( iterator1.next() ); if ( iterator2.hasNext() ) System.out.println( iterator2.next() ); }
Iterator ist ein Datentyp, der häufig in der Rückgabe verwendet wird, seltener als Parametertyp. Mit stream.iterator() ist es aber möglich, die Daten vom Stream genau an solchen Stellen zu übergeben. Einen Stream in einen Iterator zu konvertieren, um diesen dann mit hasNext()/next() abzulaufen, ist wenig sinnvoll, hierfür bietet sich genauso gut forEach(…) auf dem Stream an.
Stream ist nicht Iterable
Der Typ Stream bietet eine Methode iterator(), erweitert jedoch die Schnittstelle Iterable nicht. In der Javadoc ist bei iterator() die Bemerkung „terminale Operation“ vermerkt, denn der Iterator saugt den Stream leer, sodass ein zweiter iterator()-Aufruf auf einem Stream nicht möglich ist. Bei Klassen, die Iterable implementieren, muss ein Aufruf von iterator() beliebig oft möglich sein. Bei Streams ist das nicht gegeben, da die Streams selbst nicht für die Daten stehen wie eine Collection, die daher Iterable ist.
Iterator in Stream umwandeln
Ist auf der anderen Seite ein Iterator gegeben, lässt sich dieser nicht direkt in einen Stream bringen. Iteratoren können wie Streams unendlich sein, und es gibt keinen Weg, die Daten eines Iterators als Quelle zu benutzen. Natürlich ist es möglich, den Iterator abzulaufen und daraus einen neuen Stream aufzubauen, dann muss der Iterator aber endlich sein.
Beispiel: Die Methode ImageIO.getImageReadersBySuffix(String) liefert einen Iterator von ImageReader-Objekten – sie sollen über einen Strom zugänglich sein:
Builder<ImageReader> builder = Stream.builder(); for ( Iterator<ImageReader> iter = ImageIO.getImageReadersBySuffix( "jpg" ); iter.hasNext(); ) builder.add( iter.next() ); Stream<ImageReader> stream = builder.build(); System.out.println( stream.count() ); // 1
Einen anderen Weg geht StreamSupport.
Ist eine alte Enumeration gegeben, hilft Collections.list(enumeration).stream(), denn list(…) liefert eine ArrayList mit allen Einträgen; list(Iterator) gibt es da hingegen nicht.
iterator() von BaseStream und PrimitiveIterator.OfXXX
Die Schnittstelle Stream deklariert keine abstrakte iterator()-Methode, sondern bekommt die Methode vom Obertyp BaseStream vererbt. BaseStream ist insgesamt Basistyp von:
- Stream<T>, DoubleStream, IntStream, LongStream
Alle diese drei Typen haben damit iterator()-Methdoden, doch die Rückgaben sind unterschiedlich:
Typ | iterator()-Methdoden und Rückgabe |
Stream<T> | Iterator<T> iterator() |
DoubleStream | PrimitiveIterator.OfDouble iterator() |
IntStream | PrimitiveIterator.OfInt iterator() |
LongStream | PrimitiveIterator.OfInt iterator() |
Unterschiedliche Rückgaben der Iteratoren
PrimitiveIterator ist eine Schnittstelle aus dem Paket java.util mit eben drei inneren statischen Schnittstellen: OfDouble, OfInt und OfLong, die PrimitiveIterator erweiten. Jeder dieser drei inneren Typen hat eigene, aber symmetrische Methoden:
- default void forEachRemaining(Consumer<? super WrapperTyp> action)
- default void forEachRemaining(WrapperTypConsumer action)
- default WrapperTyp next()
- PrimitiverTyp nextPrimitiverTyp()
Statt WrapperTyp und PrimitiverTyp ist dann Double, Integer, Long und double, int, double einzusetzen.
Beispiel: Ein vom Stream abgeleiter Iterator besorgt Zahlen. Diese werden in einem anderen Stream eingesetzt.
PrimitiveIterator.OfInt counter = IntStream.iterate( 1, Math::incrementExact ).iterator(); Stream.of( "Telegram", "WhatsApp", "Facebook Messenger", "Insta" ) .map( s -> counter.nextInt() + ". " + s ) .forEach( System.out::println );
JUnit 5.1 freigegeben
Details zu den Neuerungen unter https://junit.org/junit5/docs/5.1.0/release-notes/index.html#release-notes-5.1.0
Java sollte „Inkubator“-Features bekommen.
Das bedeutet, es gibt Syntaxerweiterungen, aber die sind erst mal zum Testen.
http://openjdk.java.net/jeps/12
An incubating language or VM feature is a new feature of the Java SE Platform that is fully specified, fully implemented, and yet impermanent. It is available in a JDK feature release to provoke developer feedback based on real world use; this may lead to it becoming permanent in a future Java SE Platform.
In der Mailliste fragen die Eclipse-Bauer schon nach, ob das verpflichtend ist … es wäre blöd, wenn man sich bei den JDT viel Mühe gibt, und dann wird das doch nicht übernommen: http://mail.openjdk.java.net/pipermail/jdk-dev/2018-February/000642.html
JEP-12 ist allerdings noch nicht bestätigt.
Neuerungen in Eclipse Photon (4.8) M5
Alle Details unter https://www.eclipse.org/eclipse/news/4.8/M5/.
Der Formatter ist eines der großen Änderungen.
Auch das Behandeln von Testfällen-Code.
JEP Draft für „Raw String Literals“ in Java
In der Diskussion ist der „Back-Tick“, sodass es so aussehen würde:
File Paths Example
Traditional String Literals | Raw String Literals |
---|---|
Runtime.getRuntime().exec("\"C:\\Program Files\\foo\" bar"); |
Runtime.getRuntime().exec(`"C:\Program Files\foo" bar"`); |
Multi-line Example
Traditional String Literals | Raw String Literals |
---|---|
String html = "<html>\n" " <body>\n" + " <p>Hello World.</p>\n" + " </body>\n" + "</html>\n"; |
String html = `<html> <body> <p>Hello World.</p> </body> </html> `; |
Regular Expression Example
Traditional String Literals | Raw String Literals |
---|---|
System.out.println("this".matches("\\w\\w\\w\\w")); |
System.out.println("this".matches(`\w\w\w\w`)); |
Output:
true
Polyglot Example
Traditional String Literals | Raw String Literals |
---|---|
String script = "function hello() {\n" + " print(\'\"Hello World\"\');\n" + "}\n" + "\n" + "hello();\n"; ScriptEngine engine = new ScriptEngineManager().getEngineByName("js"); Object obj = engine.eval(script); |
String script = `function hello() { print('"Hello World"'); }
ScriptEngine engine = new ScriptEngineManager().getEngineByName(„js“); Object obj = engine.eval(script); |
Output:
"Hello World"
Database Example
Traditional String Literals | Raw String Literals |
---|---|
String query = "SELECT EMP_ID, LAST_NAME\n" + "FROM EMPLOYEE_TBL\n" + "WHERE CITY = 'INDIANAPOLIS'\n" + "ORDER BY EMP_ID, LAST_NAME;\n"; |
String query = `SELECT EMP_ID, LAST_NAME FROM EMPLOYEE_TB WHERE CITY = 'INDIANAPOLIS' ORDER BY EMP_ID, LAST_NAME; `; |
Ich bin gespannt, ob das in Java 10 kommen wird. Ich dachte schon, dass Java 10 Release wird eher klein, doch zusammen mit den var-Variablen sind das zwei kleine, aber bedeutende Sprachänderungen.
Details unter http://openjdk.java.net/jeps/8196004.