Die wichtigsten Neuerungen in der Java Enterprise Edition 7
Eine auf Entwicklerperformance und Vereinfachungen ausgelegte Java EE 6 sollte durch das Thema "Cloud" in Java EE 7 technisch stärker werden. Die Pläne stellten sich erst spät als zu ambitioniert heraus. Somit enthält die Mitte April fertiggestellte Version kaum grundlegend Neues und ist lediglich eine konsequente Abrundung der vorhandenen Funktionen.
Rund dreieinhalb Jahre sind seit dem letzten großen Versionssprung der Java Enterprise Edition (Java EE) vergangen. Eine auf Entwicklerperformance und Vereinfachungen ausgelegte Java EE 6 sollte durch das Thema "Cloud" in Java EE 7 technisch stärker werden. Die Pläne stellten sich erst spät [1] als zu ambitioniert heraus. Somit enthält die Mitte April fertiggestellte Version kaum grundlegend Neues und ist lediglich eine konsequente Abrundung der vorhandenen Funktionen.
Die Java Enterprise Edition 7 [2] entstand erstmals komplett unter Oracles Obhut. Sie umfasst als sogenannter "Umbrella" eine Menge einzelner Techniken und liefert die grundlegenden Regelungen für ihre Zusammenarbeit. Seit der Einführung der Java-EE-Plattform war eines der Hauptziele, den Entwickler von allgemeinen Infrastrukturaufgaben zu befreien. Das ermöglicht ein Container-Modell, das Zugriff und Verwaltung auf Ressourcen abstrahiert und vereinfacht. Über die Jahre wurden die Container-APIs vereinfacht, und auch Java EE 7 folgt diesem Trend. Die Ressourcendefinitionen wurden erweitert, und Applikationsserver stellen ab jetzt eine vorkonfigurierte Standard-Datenbankund eine JMS ConnectionFactory zur Verfügung. Das dürfte das Entwickeln vereinfachen und dem Programmierer eine Menge Konfigurationsarbeit ersparen.
Zu den 28 Spezifikationen in Java EE 6 sind vier vollständig neue hinzugekommen. Bei drei bestehenden wurden große inhaltliche Erweiterungen vorgenommen, die einen großen Versionssprung rechtfertigen. Bei den verbleibenden haben die Entwickler weitgehend Modellpflege betrieben. Die in Java EE 6 zum Entfernen vorgeschlagenen Spezifikationen sind in der neuen Version als "optional" gekennzeichnet und somit nicht mehr verpflichtend umzusetzen (EJB Entity Beans, JAX-RPC 1.1, JAXR 1.0 und Java EE Application Deployment 1.2).
Neu hinzugekommen sind APIs zur Arbeit mit angesagten Webtechniken. Neben vollwertigen Spezifikationen wie WebSockets (JSR 356) und JSON (JSR 353) hat man die HTML-5-Unterstützung in den JavaServer Faces (JSF) eingebaut. Das Thema Batch-Verarbeitung hat ebenfalls Einzug in die Plattform gehalten. Der JSR 352 standardisiert ein Programmiermodell für Batch-Anwendungen und bietet eine Laufzeitumgebung für Planung und Ausführung entsprechender Jobs. Einen verbesserten Zugriff auf die Ressourcen der Container ermöglichen die Concurrency Utilities. Mit der API lässt sich nunmehr zuverlässig und in Synchronisation mit den Containern mit Threads in Java EE arbeiten.
Nächste Evolution der Webservices
Obwohl JAX-RS schon in der letzten Java-EE-Version verfügbar war, enthält die Java API for RESTful Web Services (JAX-RS) 2.0 wichtige Neuerungen, die einen großen Versionssprung rechtfertigen. Herausstechendes Merkmal ist die neue Client API. Mit ihr lässt sich aus Java heraus direkt auf Endpoints zugreifen. Die Notwendigkeit von Drittanbieter-Bibliotheken entfällt somit. Im folgenden Beispiel wird ein neuer Client erstellt und eine Anfrage mit zwei Parametern an den Server Endpoint gestellt.
Client client = ClientFactory.newClient();
String name = client.target("/category/{number}/name")
.resolveTemplate("number", "5")
.queryParam("humanReadable", "true")
.request()
.get(String.class);
Neu hinzugekommen ist die asynchrone Bearbeitung von Requests zwischen Client und Server. In Anlehnung an die asynchronen Funktionen seit Servlet 3.0 wird sie mit AsyncRequest erledigt:
@GET
@Produces("application/plain")
public void longRunning(@Suspended final AsyncResponse ar) {
Executors.newSingleThreadExecutor().submit(
new Runnable() {
@Override
public void run() {
longRunning();
ar.resume("Hello heise Developer!");
}
});
}
Mit Message-Filtern und Entity-Interceptors kann man auf Request und Response zugreifen und beide serverseitig bearbeiten. Aber auch beliebte Aspekte wie Logging können Entwickler elegant mit Filtern umsetzen.
@Provider
class LoggingFilter implements RequestFilter {
@Override
public FilterAction preFilter(FilterContext context) throws IOException {
log(ctx.getRequest());
return FilterAction.NEXT;
}
//...
}
Dieser Filter ist dann nur noch über einen @Qualifyer zu binden und lässt sich direkt an einer JAX-RS-Ressource verwenden:
@Logged
@GET
@Produces("text/plain")
@Path("/hello")
public String hello(){
return "Hello @heisedc!";
}
Die Arbeit mit eingebauten Klassen wie String ist damit vergleichsweise einfach. Wird mit eigenen Objekten gearbeitet, ist das Mapping zwischen diesen und der serialisierten Ausgabe (JSON, XML) manuell zu erledigen. Die technischen Möglichkeiten schafft die Spezifikation mithilfe sogenannter Entity Provider. In ihnen lässt sich die Nutzlast der Nachrichten vom einen in das andere Format umwandeln. Analog dazu wurden die beiden zuständigen APIs MessageBodyReader und MessageBodyWriter benannt. Für ein fiktives Objekt "Person" würde ein entsprechender Reader folgendermaßen aussehen:
@Provider
@Produces("application/json")
public class PersonReader implements MessageBodyReader<Person> {
//...
@Override
public void readFrom(Person p, Class<Person> type, Type t, Annotation[]
as, MediaType mt, MultivaluedMap<String, Object> mm, OutputStream out)
throws IOException, WebApplicationException {
//...
}
Die Entity Provider bieten dabei lediglich den Einsprung in JAX-RS an. Das konkrete De-/Serialisieren der Objekte ist noch zu implementieren. Leider bieten weder Spezifikation noch Referenzimplementierung hierfür etwas serienmäßig an. Der Entwickler hat die Wahl zwischen bestehenden Mechanismen, wie ihn beispielsweise EclipseLink mit MOXy [3] anbietet, oder er kann selbst tätig werden.
JSON, JSF, Servlet, Bean Validation
JSON als Arbeitskollege
Für Letzteres steht jetzt mit der Java API for JSON Processing ein Handwerkszeug zur Arbeit mit JSON (JavaScript Object Notation) bereit. Es werden eine Streaming API (JsonParser, JsonGenerator) und eine DOM API (JsonReader, JsonWriter) angeboten. Während die erste API ereignisgetrieben agiert, lässt sich mit der zweiten auf Objektebene arbeiten. Um JSON mit der Streaming API auf System.out zu schreiben, benötigt man lediglich JsonGenerator:
JsonGeneratorFactory factory = Json.createGeneratorFactory();
JsonGenerator gen = factory.createGenerator(System.out);
Einzelne Objekte werden der Ausgabe direkt hinzugefügt:
gen.writeStartObject().write("Java EE", "7").write("heise",
"Developer").writeEnd();
JsonWriter geht dabei objektgetrieben vor und ermöglicht das Erzeugen spezieller JSON-Datentypen:
JsonArray jsonArray = new JsonArrayBuilder().add(new JsonObjectBuilder()
.add("Java EE","7")).add(new JsonObjectBuilder()
.add("heise","Developer")).build();
An der Oberfläche
Passend zur Unterstützung zeitgemäßer Webtechniken versteht sich JSF jetzt mit HTML-5-konformem Markup. Die als data-* bekannten eigenen Datenattribute wurden bisher von den JSF-Komponenten verworfen und nicht gerendert. Genau das lässt sich nun mit einem neuen JSF-Tag erreichen.
<h:inputText value="#{person.email}">
<f:passThroughAttribute name="data-length" value="10"/>
</h:inputText>
Alle JSF-Komponenten verstehen den neuen Weg. Entlang dieser Kleinigkeit gibt es viele weitere Änderungen. Dazu gehören die neuen View Actions, die Request-Variablen an das Modell binden können, eine mit AJAX erstellte File-Upload-Komponente, die Einführung von Stateless Views und eine überarbeitete Integration von CDI (Contexts and Dependency Injection) inklusive der Anpassung der Scopes. Eines der großen neuen Funktionspakete stellt Faces Flow dar. Hierbei handelt sich es um eine Erweiterung der Navigation, mit der es einfacher ist, geführte Dialogstrecken für Anwender zur Verfügung zu stellen. Diese werden Wizzard genannt und haben neben einer definierten Abfolge von Dialogen einen eigenen Gültigkeitsbereich für die Daten. Flows lassen sich über den <f:metadata>-Tag direkt in Facelets verwenden, aber auch programmatisch erzeugen. Sie werden ähnlich der impliziten Navigation direkt als Action gestartet, beispielsweise über:
<h:commandLink value="Enter flow" action="someFlowName" />
Wenn es definiert ist, ist eine zugehörige JavaBean während des Flows verfügbar:
@Named
@FlowScoped(id = "someFlowName")
public class SomBean {
public String someReturn() {
return "/somePage.xhtml";
}
}
Zu Ihren Diensten
Hinter der neuen Version der Servlets verbergen sich hauptsächlich drei kleinere Erweiterungen. Wichtigster Aspekt ist die Umsetzung des seit HTTP 1.1 (RFC 2616) möglichen Protokoll-Upgrades – dieser Mechanismus ermöglicht die neue WebSockets-Spezifikation erst. Der neue javax.servlet.http.HttpUpgradeHandler ist dafür zuständig. Ein schönes Beispiel liefert Spezifikations-Lead Shing Wai Chan in seinem Blog [4].
Auch in Sachen Sicherheit hat sich etwas getan. So werden bisher nur die HTTP-Methoden geschützt, die explizit in der web.xml definiert sind. Vielfach sind das nur GET und POST gewesen. Die übrigen (HEAD, PUT, DELETE etc.) verblieben zumeist per Standardeinstellung ungeschützt. Das lässt sich nun umdrehen und somit alles schützen, was nicht explizit freigegeben wird (<deny-uncovered-http-methods/>). Auch hat man eine neue Semantik "Jeder authentisierte User" eingeführt, was die Prüfung auf die Gesamtsumme aller Rollen vereinfacht. Dabei gibt es einen Unterschied: "*" bezieht sich auf jede in der web.xml definierte Rolle und "**" auf jeden authentifizierten Nutzer.
Viel gewonnen
Die Zusammenarbeit mit der Bean-Validation-Spezifikation wurde deutlich verbessert. Jetzt lassen sich Methodenparameter validieren, nicht nur mit Standard-Validatoren (@NotNull), sondern auch mit eigenen, nutzerdefinierten Constraints. Damit ist gleich die größte Neuerung in Bean Validation beschrieben. Neben der Methodenvalidierung kann man Konstruktor-Validierungen durchführen, und auch hier wurde die Integration in die CDI-Spezifikation vorangetrieben. Es ist jetzt beispielsweise möglich, @Inject in Validatoren zu verwenden. In Meldungen können Entwickler jetzt Expression-Language-Ausdrücke einsetzen. Das führt zu einer deutlich flexibleren Darstellung.
javax.validation.constraints.DecimalMax.message= Muss weniger
${inclusive == true ? 'gleich sein zu ' : ''}{value}
Die Expression Language unterstützt in Version 3.0 neben neuen Operatoren nun Collections und Lambda-Ausdrücke. Letztere allerdings nur zukünftig unter Java SE 8. Die EL lässt sich jetzt auch alleinstehend verwenden:
ELProcessor el = new ELProcessor;
Object result = el.eval("'Hello, ' + user.name");
Und es lassen sich eigene Resolver oder Klassen hinzufügen. Eigene Typ-Konverter und EvaluationListener runden das Bild ab und machen sie zu einer komplett eigenständigen und mächtigen Spezifikation.
Concurrency, WebSockets, JMS, Batch
Mal so nebenbei
Mit den Concurrency Utilities lassen sich über eine einfache API konkurrierende Aktionen von Anwendungskomponenten ausführen, ohne die Container-Integrität zu gefährden. Die direkte Verwendung der Concurrency APIs von Java SE in Java-EE-Containern ist verboten, weil sich diese der Ressourcenverwaltung durch die Container entziehen und zu Stabilitätsproblemen führen. Daher sind die Concurrency Utilities nicht
mehr als eine Java-EE-konforme Erweiterung des JSR 166 in Java SE. Die vorhandenen Funktionen verwaltet nunmehr der Container. Statt eines java.util.concurrent.ExecutorService gibt es jetzt das Enterprise-Gegenstück javax.enterprise.concurrent.ManagedExecutorService. Eine Standard-Instanz steht via JNDI (Java Naming and Directory Interface) bereit, sie lässt sich aber auch direkt injizieren:
@Resource(lookup="DefaultManagedExecutorService")
ManagedExecutorService executor;
Die auszuführende Aufgabe wird als Task bezeichnet und implementiert dabei das Runnable- oder Callable-Interface.
public class MeineAufgabe implements Runnable {
@Override
public void run() {
//...
}
}
Der Task wird dann über den ManagedExecutorService ausgeführt:
Collection tasks = new ArrayList();
tasks.add(new MeineAufgabe());
executor.invokeAny(tasks);
Neben dem Task ohne Rückgabewert gibt es noch den Callable, der einen Rückgabewert haben kann. CDI Beans können ebenfalls Tasks sein. Hierbei sollte allerdings auf den Scope geachtet werden. Nur @Application oder @Dependent Scope lassen sich als Tasks verwenden. Mit javax.enterprise.concurrent.ManagedScheduledExecutorService kann der Entwickler zeitgesteuerte Aufgaben ausführen. Der Aufruf erfolgt analog zum ExecutorService, einzig die Angabe der relevanten Zeiten ist noch zusätzlich erforderlich.
ScheduledFuture<?> f = executor.schedule(new MeineAufhabe (), 15,
TimeUnit.SECONDS);
Der Code führt die Aufgabe mit 15 Sekunden Startverzögerung aus. Über den sogenannten Container Context werden Funktionen von Anwendungskomponenten wie Classloader, Namespaces und Security bereitgestellt.
In der Gegenwart des Web angekommen
Wichtiger Teil heutiger Webtechniken, die in die Java EE Einzug gehalten haben, sind die WebSockets [5]. Als bidirektionales Kommunikationsprotokoll über TCP erlauben sie die direkte Kommunikation zwischen Server und Client. Dabei sind die WebSockets ein Request for Comments (RFC) der Internet Engineering Task Force (IETF), die HTML-5-fähige Browser auch mit zugehöriger JavaScript API ausgestalten. Im Gegensatz zu HTTP wird eine TCP-Verbindung dabei persistent aufrechterhalten. Der derzeitige Stand des JSR 356 bildet nicht alle Möglichkeiten ab, sondern fokussiert sich auf die serverseitige Bereitstellung der WebSocket Endpoints, die Entgegennahme von Text-, Binär- und Kontroll-Nachrichten, die Lebenszyklus-Events sowie die Integration in Java EE Security. Ein einfacher Endpunkt für einen Chat sieht so aus:
@ServerEndpoint("/chat/{room}")
public class ChatServer {
@OnMessage
public void receiveMessage(String message, @PathParam("room") String room) {
//...
}
}
Die mit @onMessage annotierte Methode wird beim Empfang einer Nachricht eines Clients verwendet. Je nach Nachrichtenformat wird über den Methodenparameter die Behandlung von Textnachrichten via String, Binärnachrichten via byte[] und Streams via InputStream ermöglicht. Mit @PathParam lassen sich primitive Java-Typen oder Strings im Server-Endpoint verwenden. Neben @OnMessage gibt es noch die Lebenszyklus-Methoden (@OnOpen, @OnClose und @OnError), die sich ausimplementieren lassen. CDI wird vollständig unterstützt. Alternativ zu den Annotationen lässt sich ein Server Endpoint auch via API komplett programmatisch erstellen und somit auch in Java SE bereitstellen. Im Idealfall ist ein im Browser ausgeführter JavaScript-Client die Gegenstelle für den Server.
var websocket = new WebSocket("ws://localhost:8080/chatapp/chat");
Aber auch Java-Klassen können Client sein. Dafür wird die @ClientEndpoint-Annotation angeboten:
@ClientEndpoint
public class ChatClient {
//...
}
Hier stehen wieder die Lebenszyklus-Events mit den entsprechend annotierten Methoden analog zum Server zur Verfügung. Mit Encodern und Decodern können Entwickler analog zu JAX-RS applikationsspezifische Datentypen serialisieren. Leider können sie hier nicht einfach Provider registrieren, sondern müssen sie dem Server Endpoint mitgegeben.
@ServerEndpoint(value = "/personservice",
encoders = {PersonEncoder.class},
decoders = {PersonDecoder.class})
Die bekannten Security-Constraints aus dem web.xml Deployment Descriptor greifen auch für WebSocket Endpoints.
Jahre des Stillstands überwunden
Nach gut neun Jahren Stillstand lässt sich die neue Version der Java Message Services (JMS) als die umfangreichste Veränderung bezeichnen. Durch die Anwendung der Mittel aus Java SE] 7 wie "Try-with-resources", aber auch dank Dependency Injection ist die Verwendung der API schlank und einfach geworden. So wurden Connection- und Session-Objekte im neuen JMSContext zusammengefasst. Statt mit zweien arbeiten zu müssen, reicht jetzt der neue Context, der auch injiziert werden kann. Er ist also weder explizit zu erstellen noch zu schließen.
@Inject JMXContext context;
Die Vereinfachung der APIs hat man aber noch weiter vorangetrieben. So lässt sich dank neuer Producer-Methoden jetzt flüssiger arbeiten. Das Senden einer JMS-Nachricht auf dem neuen Weg schrumpft deutlich:
TextMessage textMessage = context.createTextMessage(body);
context.createProducer().setPriority(1).setProperty("foo",
"bar").send(demoQueue, textMessage);
Dabei sind die Producer "leichtgewichtig" und können bei Bedarf erzeugt werden. Die Notwendigkeit, sie zwischenzuspeichern, entfällt damit komplett. Überhaupt ist ein Nachrichtenobjekt nicht mehr zu instanziieren. Mit JMS 2.0 lassen sich die gewünschten Nutzdaten dem Producer direkt übergeben:
context.createProducer().send(demoQueue,"Hallo iX");
Andersherum entfällt beim Empfangen nunmehr eine Typumwandlung auf eine genaue Klasse.
JMSConsumer consumer = context.createConsumer(demoQueue);
String result = "Empfangen " + consumer.receiveBody(String.class, 1000);
Mit den Änderungen hat man die Arbeit stark vereinfacht und eine Menge überflüssigen Code verhindert. Dabei wirken sich die Änderungen in diesem Punkt nicht nur auf die Arbeit in der Java-EE-Spezifikation, sondern auch auf Java SE aus. Im Java-EE-Container erfordern die Neuerungen den Einsatz eines Resource-Adapters, was aber für die Entwickler unbemerkt die Server erfüllen sollten.
Von der Spring-Community inspiriert
Es hat lange gedauert, bis Batch-Anwendungen auch in die Java Enterprise Edition Einzug gehalten hat. Stark angelehnt an die Konzepte von Spring Batch und unter der Regie von IBM steht der JSR 352 bereit zur Batch-Verarbeitung. Die Grundidee ist die Verarbeitung einer Serie von Jobs, die ohne Interaktion Massendaten in langlaufenden Schritten verändern. Ein Job ist dabei das Hauptobjekt. Es untergliedert sich in einzelne Schritte ("steps"), die nach bekanntem Batch-Pattern (Lesen, Bearbeiten, Schreiben) Aufgaben ausführen. Gestartet werden Batch-Jobs über den sogenannten Batch-Operator:
JobOperator jo = BatchRuntime.getJobOperator();
Properties jobParams = new Properties();
jobParams.put("file.url", " testdata.txt");
long jobId = jo.start("extract-cities", jobParams);
Im obigen Beispiel wird dem Batch-Job noch Properties mitgegeben. Dies wird zusammen mit dem Namen der eigentlichen Batch-Beschreibung an die start-Methode transferiert. Unter dem übergebenen Namen findet sich unter META-INF/batch-jobs/ ein gleichnamiges XML-Dokument, das den Job beschreibt.
<job id="extractCity" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
<step id="populateCities" >
<chunk>
<reader ref="entryReader" />
<processor ref="entryProcessor"/>
<writer ref="entryWriter"/>
</chunk>
</step>
</job>
Dabei beschreiben job, chunk und step den elementorientierten Bearbeitungstyp. Mit einem sogenannten Batchlet lässt sich auch der aufgabenorientierte Bearbeitungstyp umsetzen. Die drei hauptsächlichen Klassen werden aus dem XML mit ihrem Bean-Namen angesprochen. Demzufolge ergibt sich, dass für Reader, Processor und Writer jeweils eine entsprechende Klasse umzusetzen ist:
@Named("entryReader")
public class EntryReader extends AbstractItemReader {
//...
@Override
public String readItem() {
//...
}
@Named("entryProcessor")
public class EntryProcessor implements ItemProcessor {
//...
@Override
public Object processItem(Object o) throws Exception {
//...
}
@Named("entryWriter")
public class EntryWriter extends AbstractItemWriter {
//...
@Override
public void writeItems(List<Object> list) throws Exception {
//...
}
Fazit
Und noch viel mehr
Damit sind noch längst nicht alle Änderungen erläutert. Vor allen in den zahlreichen Maintenance-Releases sind eine Menge Vereinfachungen und Verallgemeinerungen zu finden. Das Transaktions-Handling der Java Transaction API (JTA) wurde angepasst und von den EJBs entkoppelt. Damit ist die Verwendung von Transaktionen auf ManagedBeans in der Plattform vereinheitlicht worden. Im EJB-Bereich sind unter anderem lokale, asynchrone Session Beans und nicht in der Datenbank persistierte Timer Beans im EJB-Lite-Profil hinzugekommen. Der Embeddable EJB Container implementiert jetzt auch das AutoClosable-Interface von Java SE 7. Vergleichbar viele Kleinigkeiten sind es bei CDI: Fehlerbehebungen, Klarstellungen in der Spezifikation und knapp drei Handvoll neue Funktionen wie die Injektion des Servlet Context oder die Bereitstellung sogenannter applikationsübergreifender Lebenszyklus-Events für Komponenten (bspw @Initialized, @Destroyed).
Die mit Java EE 6 eingeführten Profile existieren weiterhin. Es wurden allerdings keine neuen ergänzt. Die für die Webentwicklung angepasste Untermenge des vollständigen Dokuments enthält jetzt drei zusätzliche Spezifikationen: JAX-RS, WebSockets und JASON-P.
GlassFish 4.0 als Referenzimplementierung
Mit Verabschiedung der Spezifikation geht auch die Referenzimplementierung des GlassFish [6] an den Start [7]. Recht kurzfristig steht der erste konforme Applikationsserver für die Entwicklergemeinde bereitstehen. Die Modularisierungsträume der letzten Jahre erfüllt Java EE 7 leider nicht. Hauptgrund hierfür ist das verschobene Java-eigene Modulsystem Jigsaw. Dennoch bleibt Java EE die etablierte und weitverbreitete Plattform in der Unternehmenswelt. Mit einer zweistelligen Zahl zertifizierter Server wurde am Markt eine breite Nutzerbasis geschaffen. Das hat mehr als drei Jahre gebraucht. Vermutlich ist das auch der Zeitraum, den es braucht, bis Kunden und Hersteller auf die jetzt neue Version umstellen.
Für Entwickler bleibt also genügend Zeit, sich mit den an vielen Stellen vereinfachten Techniken auseinanderzusetzen. Derzeit mangelt es noch an Code-Beispielen. Vieles muss sich der Interessierte aus den Spezifikationen selbst oder aus JavaDocs zusammensuchen. Mit dem offiziellen Start des GlassFish 4.0 wird vermutlich auch das Java-EE-Tutorial umgestellt sein, und es werden bereits die ersten Publikationen verfügbar sein. Die Java EE Expert Group geht wohl auch bald in die nächste Runde. Mit Java EE 8 – derzeit für 2015 vorgesehen – soll dann doch das Thema "Cloud kommen.
Markus Eisele [8]
ist Principal IT Architect bei der msg systems AG in München sowie Mitglied der Java EE 7 Expert Group, des iJUG e.V sowie Oracle ACE Director.
Überblick
Spezifikationen im Überblick
(ane [34])
URL dieses Artikels:
https://www.heise.de/-1886333
Links in diesem Artikel:
[1] https://blogs.oracle.com/theaquarium/entry/java_ee_7_roadmap
[2] http://jcp.org/en/jsr/summary?id=342
[3] http://blog.bdoughan.com/2012/03/moxy-as-your-jax-rs-json-provider.html
[4] https://weblogs.java.net/blog/swchan2/archive/2013/05/07/protocol-upgrade-servlet-31-example
[5] https://www.heise.de/hintergrund/WebSocket-Annaeherung-an-Echtzeit-im-Web-1260189.html
[6] https://glassfish.dev.java.net/
[7] https://www.heise.de/news/Referenzimplementierung-fuer-Java-EE-7-GlassFish-4-0-erschienen-1886175.html
[8] http://blog.eisele.net
[9] http://java.net/projects/javaee-spec/
[10] http://jax-rs-spec.java.net/
[11] https://jax-ws.java.net/
[12] https://jaxb.java.net/
[13] http://jax-rpc.java.net/
[14] http://javaserverfaces.java.net/
[15] http://el-spec.java.net/
[16] https://jstl.java.net/
[17] https://github.com/jboss/cdi/wiki
[18] http://beanvalidation.org/
[19] http://ejb-spec.java.net/
[20] http://jpa-spec.java.net/
[21] https://java.net/projects/javaee-spec/pages/CommonAnnotations1_2MR
[22] https://jms-spec.java.net/
[23] http://jta-spec.java.net/
[24] http://javamail.java.net/
[25] http://jaspic-spec.java.net/
[26] http://jacc-spec.java.net/
[27] http://openjdk.java.net/groups/jmx/
[28] http://sjsxp.java.net/
[29] https://interceptors-spec.java.net/
[30] http://jbatch.java.net/
[31] http://json-processing-spec.java.net/
[32] http://websocket-spec.java.net/
[33] http://concurrency-ee-spec.java.net/
[34] mailto:ane@heise.de
Copyright © 2013 Heise Medien