Gives you all the tools to exploit the "Write Once, Run Anywhere" principle

Asity is here chirping *universally reusable web fragments on the JVM*

© Shutterstock /Artush  

Since summer is well upon us, how about taking a quick trip to exotic Madagascar to meet some sweet asity birds? Or, we can just build universally reusable web fragments on the JVM with Asity, a lightweight abstraction layer for various web frameworks on the Java Virtual Machine that makes the long-lived “Write Once, Run Anywhere” concept a fascinating reality!

Have you met Asity? It is probably the most Java-intelligent exotic bird you’ll ever meet!

By establishing an ecosystem of universally reusable web fragments that run across different frameworks in the Java ecosystem, Asity gives all the tools (and reasons) you need to achieve and exploit the “Write Once, Run Anywhere” principle that has been central to the Java ecosystem for ages!

According to the official web page, Asity provides abstractions for HTTP and WebSocket, and implementations per framework, called bridges, which are transparent to end-users and don’t affect the framework’s performance, productivity and philosophy.

SEE ALSO: Meet Jib: Containerizing a Java application has never been easier

Feeling intrigued? Wait until you hear the news!

Just hours ago, Asity 2.0.0 was officially released and I cannot wait to give you a quick tour of how working with reusable web fragments on the JVM looks like!

More “Write Once, Use Anywhere” things coming your way

In order to demonstrate how to build an echo fragment which simply responds to the client with whatever data the client sent, here is a comprehensive example of Asity 2.

Add the following dependencies:

<!-- To write a web fragment -->
<!-- To run a web fragment on Spring WebFlux 5 -->

And the following class:

package io.cettia.asity.example.spring.webflux5;

import io.cettia.asity.action.Action;
import io.cettia.asity.bridge.spring.webflux5.AsityHandlerFunction;
import io.cettia.asity.bridge.spring.webflux5.AsityWebSocketHandler;
import io.cettia.asity.http.HttpStatus;
import io.cettia.asity.http.ServerHttpExchange;
import io.cettia.asity.websocket.ServerWebSocket;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
import org.springframework.web.reactive.socket.WebSocketHandler;

import java.nio.ByteBuffer;
import java.util.LinkedHashMap;
import java.util.Map;

import static org.springframework.web.reactive.function.server.RequestPredicates.headers;
import static org.springframework.web.reactive.function.server.RequestPredicates.path;

public class EchoServer {
  public Action<ServerHttpExchange> httpAction() {
    return new HttpEchoServer();

  public Action<ServerWebSocket> wsAction() {
    return new WebSocketEchoServer();

  public RouterFunction<ServerResponse> httpMapping() {
    AsityHandlerFunction asityHandlerFunction = new AsityHandlerFunction().onhttp(httpAction());

    return RouterFunctions.route(
        // Excludes WebSocket handshake requests
        .and(headers(headers -> !"websocket".equalsIgnoreCase(headers.asHttpHeaders().getUpgrade()))), asityHandlerFunction);

  public HandlerMapping wsMapping() {
    AsityWebSocketHandler asityWebSocketHandler = new AsityWebSocketHandler().onwebsocket(wsAction());
    Map<String, WebSocketHandler> map = new LinkedHashMap<>();
    map.put("/echo", asityWebSocketHandler);

    SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();

    return mapping;

  public WebSocketHandlerAdapter webSocketHandlerAdapter() {
    return new WebSocketHandlerAdapter();

  public static void main(String[] args) {, args);

  public static class HttpEchoServer implements Action<ServerHttpExchange> {
    public void on(ServerHttpExchange http) {
      // Reads request URI, method and headers
      System.out.println(http.method() + " " + http.uri());
      http.headerNames().stream().forEach(name -> System.out.println(name + ": " + String.join(", ", http.headers(name))));

      // Writes response status code and headers
      http.setStatus(HttpStatus.OK).setHeader("content-type", http.header("content-type"));

      // Reads a chunk from request body and writes it to response body
      http.readAsText().onchunk((String chunk) -> http.write(chunk));
      // If request body is binary,
      // http.readAsBinary().onchunk((ByteBuffer binary) -> http.write(binary));

      // Ends response if request ends
      http.onend((Void v) -> http.end());

      // Exception handling
      http.onerror((Throwable t) -> t.printStackTrace()).onclose((Void v) -> System.out.println("disconnected"));

  public static class WebSocketEchoServer implements Action<ServerWebSocket> {
    public void on(ServerWebSocket ws) {
      // Reads handshake request URI and headers
      ws.headerNames().stream().forEach(name -> System.out.println(name + ": " + String.join(", ", ws.headers(name))));

      // Sends the received text frame and binary frame back
      ws.ontext((String text) -> ws.send(text)).onbinary((ByteBuffer binary) -> ws.send(binary));

      // Exception handling
      ws.onerror((Throwable t) -> t.printStackTrace());

As you would expect, HttpEchoServer and WebSocketEchoServer are web fragments and can be reused in other frameworks through other bridges like asity-bridge-spring-webmvc4. You can also see that a bridge implementation is completely transparent to end-users who still have full control over web fragments on frameworks they selected.

Asity 2.0.0 now supports Java API for WebSocket 1, Servlet 3, Spring WebFlux 5, Spring MVC 4, Vert.x 3, Netty 4, Grizzly 2, Vert.x 2 and Atmosphere 2. You can find a list of working examples per supported frameworks here and the full documentation here.


Eirini-Eleni Papadopoulou
Eirini-Eleni Papadopoulou was the editor for Coming from an academic background in East Asian Studies, she decided that it was time to go back to her high-school hobby that was computer science and she dived into the development world. Other hobbies include esports and League of Legends, although she never managed to escape elo hell (yet), and she is a guest writer/analyst for competitive LoL at TGH.

Inline Feedbacks
View all comments