You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@johnzon.apache.org by rm...@apache.org on 2015/03/24 16:30:04 UTC

incubator-johnzon git commit: JOHNZON-41 jsr 356 integration, note: still some work to do on client annotation endpoint integration but didnt find a right api yet

Repository: incubator-johnzon
Updated Branches:
  refs/heads/master e98915914 -> 29a79edb9


JOHNZON-41 jsr 356 integration, note: still some work to do on client annotation endpoint integration but didnt find a right api yet


Project: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/commit/29a79edb
Tree: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/tree/29a79edb
Diff: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/diff/29a79edb

Branch: refs/heads/master
Commit: 29a79edb9a9845a01098188c418331319079009d
Parents: e989159
Author: Romain Manni-Bucau <rm...@apache.org>
Authored: Tue Mar 24 16:29:57 2015 +0100
Committer: Romain Manni-Bucau <rm...@apache.org>
Committed: Tue Mar 24 16:29:57 2015 +0100

----------------------------------------------------------------------
 johnzon-websocket/pom.xml                       |  91 +++++++++++++++
 .../websocket/internal/jsr/FactoryLocator.java  |  89 +++++++++++++++
 .../websocket/internal/jsr/JsrDecoder.java      |  53 +++++++++
 .../websocket/internal/jsr/JsrEncoder.java      |  53 +++++++++
 .../internal/mapper/MapperLocator.java          |  62 +++++++++++
 .../johnzon/websocket/jsr/JsrArrayDecoder.java  |  31 ++++++
 .../johnzon/websocket/jsr/JsrArrayEncoder.java  |  31 ++++++
 .../johnzon/websocket/jsr/JsrObjectDecoder.java |  34 ++++++
 .../johnzon/websocket/jsr/JsrObjectEncoder.java |  31 ++++++
 .../websocket/jsr/JsrStructureDecoder.java      |  34 ++++++
 .../websocket/jsr/JsrStructureEncoder.java      |  31 ++++++
 .../websocket/mapper/JohnzonTextDecoder.java    | 110 +++++++++++++++++++
 .../websocket/mapper/JohnzonTextEncoder.java    |  47 ++++++++
 .../apache/johnzon/websocket/JsrCodecTest.java  |  93 ++++++++++++++++
 .../johnzon/websocket/MapperCodecTest.java      |  95 ++++++++++++++++
 .../websocket/endpoint/ClientEndpointImpl.java  |  53 +++++++++
 .../endpoint/JsrClientEndpointImpl.java         |  41 +++++++
 .../endpoint/JsrServerEndpointImpl.java         |  50 +++++++++
 .../johnzon/websocket/endpoint/Message.java     |  42 +++++++
 .../websocket/endpoint/ServerEndpointImpl.java  |  44 ++++++++
 .../websocket/endpoint/ServerReport.java        |  71 ++++++++++++
 .../src/test/resources/arquillian.xml           |  38 +++++++
 pom.xml                                         |   1 +
 23 files changed, 1225 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/pom.xml
----------------------------------------------------------------------
diff --git a/johnzon-websocket/pom.xml b/johnzon-websocket/pom.xml
new file mode 100644
index 0000000..43e9366
--- /dev/null
+++ b/johnzon-websocket/pom.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>apache-johnzon</artifactId>
+    <groupId>org.apache.johnzon</groupId>
+    <version>0.8-incubating-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>johnzon-websocket</artifactId>
+  <name>Johnzon :: WebSocket</name>
+
+  <properties>
+    <tomcat.version>7.0.59</tomcat.version>
+    <tomee.version>1.7.1</tomee.version>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.tomcat</groupId>
+      <artifactId>tomcat-websocket-api</artifactId>
+      <version>${tomcat.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.tomcat</groupId>
+      <artifactId>tomcat-servlet-api</artifactId>
+      <version>${tomcat.version}</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.johnzon</groupId>
+      <artifactId>johnzon-mapper</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.jboss.arquillian.junit</groupId>
+      <artifactId>arquillian-junit-container</artifactId>
+      <version>1.1.7.Final</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.openejb</groupId>
+      <artifactId>arquillian-tomee-remote</artifactId>
+      <version>${tomee.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.openejb</groupId>
+      <artifactId>apache-tomee</artifactId>
+      <version>${tomee.version}</version>
+      <type>zip</type>
+      <classifier>jaxrs</classifier>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.12</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.tomcat</groupId>
+      <artifactId>tomcat7-websocket</artifactId>
+      <version>${tomcat.version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/jsr/FactoryLocator.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/jsr/FactoryLocator.java b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/jsr/FactoryLocator.java
new file mode 100644
index 0000000..48463d9
--- /dev/null
+++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/jsr/FactoryLocator.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.internal.jsr;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import javax.json.Json;
+import javax.json.JsonReaderFactory;
+import javax.json.JsonWriterFactory;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.annotation.WebListener;
+
+@WebListener
+public class FactoryLocator implements ServletContextListener {
+    private static final Map<ClassLoader, JsonReaderFactory> READER_FACTORY_BY_LOADER = new ConcurrentHashMap<ClassLoader, JsonReaderFactory>();
+    private static final Map<ClassLoader, JsonWriterFactory> WRITER_FACTORY_BY_LOADER = new ConcurrentHashMap<ClassLoader, JsonWriterFactory>();
+    private static final String READER_ATTRIBUTE = FactoryLocator.class.getName() + ".readerFactory";
+    private static final String WRITER_ATTRIBUTE = FactoryLocator.class.getName() + ".writerFactory";
+
+    @Override
+    public void contextInitialized(final ServletContextEvent servletContextEvent) {
+        final ClassLoader classLoader = servletContextEvent.getServletContext().getClassLoader();
+
+        final JsonReaderFactory reader = newReadFactory();
+        READER_FACTORY_BY_LOADER.put(classLoader, reader);
+        servletContextEvent.getServletContext().setAttribute(READER_ATTRIBUTE, reader);
+
+        final JsonWriterFactory writer = newWriterFactory();
+        WRITER_FACTORY_BY_LOADER.put(classLoader, writer);
+        servletContextEvent.getServletContext().setAttribute(WRITER_ATTRIBUTE, reader);
+    }
+
+    @Override
+    public void contextDestroyed(final ServletContextEvent servletContextEvent) {
+        final ClassLoader classLoader = servletContextEvent.getServletContext().getClassLoader();
+        READER_FACTORY_BY_LOADER.remove(classLoader);
+        WRITER_FACTORY_BY_LOADER.remove(classLoader);
+    }
+
+    public static JsonReaderFactory readerLocate() {
+        ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        if (loader == null) {
+            loader = FactoryLocator.class.getClassLoader();
+        }
+        final JsonReaderFactory factory = READER_FACTORY_BY_LOADER.get(loader);
+        if (factory == null) {
+            return newReadFactory();
+        }
+        return factory;
+    }
+
+    public static JsonWriterFactory writerLocate() {
+        ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        if (loader == null) {
+            loader = FactoryLocator.class.getClassLoader();
+        }
+        final JsonWriterFactory factory = WRITER_FACTORY_BY_LOADER.get(loader);
+        if (factory == null) {
+            return newWriterFactory();
+        }
+        return factory;
+    }
+
+    private static JsonReaderFactory newReadFactory() {
+        return Json.createReaderFactory(Collections.<String, Object>emptyMap());
+    }
+
+    private static JsonWriterFactory newWriterFactory() {
+        return Json.createWriterFactory(Collections.<String, Object>emptyMap());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/jsr/JsrDecoder.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/jsr/JsrDecoder.java b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/jsr/JsrDecoder.java
new file mode 100644
index 0000000..2edb3c9
--- /dev/null
+++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/jsr/JsrDecoder.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.internal.jsr;
+
+import java.io.IOException;
+import java.io.Reader;
+import javax.json.JsonReader;
+import javax.json.JsonReaderFactory;
+import javax.websocket.DecodeException;
+import javax.websocket.Decoder;
+import javax.websocket.EndpointConfig;
+
+public abstract class JsrDecoder<T> implements Decoder.TextStream<T> {
+    private JsonReaderFactory factory;
+
+    protected abstract T doRead(JsonReader jsonReader);
+
+    @Override
+    public void init(final EndpointConfig endpointConfig) {
+        factory = FactoryLocator.readerLocate();
+    }
+
+    @Override
+    public T decode(final Reader reader) throws DecodeException, IOException {
+        final JsonReader jsonReader = factory.createReader(reader);
+        try {
+            return doRead(jsonReader);
+        } finally {
+            jsonReader.close();
+        }
+    }
+
+    @Override
+    public void destroy() {
+        // no-op
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/jsr/JsrEncoder.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/jsr/JsrEncoder.java b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/jsr/JsrEncoder.java
new file mode 100644
index 0000000..917482b
--- /dev/null
+++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/jsr/JsrEncoder.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.internal.jsr;
+
+import java.io.IOException;
+import java.io.Writer;
+import javax.json.JsonWriter;
+import javax.json.JsonWriterFactory;
+import javax.websocket.EncodeException;
+import javax.websocket.Encoder;
+import javax.websocket.EndpointConfig;
+
+public abstract class JsrEncoder<T> implements Encoder.TextStream<T> {
+    private JsonWriterFactory factory;
+
+    protected abstract void doWrite(JsonWriter writer, T t);
+
+    @Override
+    public void init(final EndpointConfig endpointConfig) {
+        factory = FactoryLocator.writerLocate();
+    }
+
+    @Override
+    public void destroy() {
+        // no-op
+    }
+
+    @Override
+    public void encode(final T t, final Writer writer) throws EncodeException, IOException {
+        final JsonWriter jsonWriter = factory.createWriter(writer);
+        try {
+            doWrite(jsonWriter, t);
+        } finally {
+            jsonWriter.close();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/mapper/MapperLocator.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/mapper/MapperLocator.java b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/mapper/MapperLocator.java
new file mode 100644
index 0000000..9145694
--- /dev/null
+++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/mapper/MapperLocator.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.internal.mapper;
+
+import org.apache.johnzon.mapper.Mapper;
+import org.apache.johnzon.mapper.MapperBuilder;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.annotation.WebListener;
+
+@WebListener
+public class MapperLocator implements ServletContextListener {
+    private static final Map<ClassLoader, Mapper> MAPPER_BY_LOADER = new ConcurrentHashMap<ClassLoader, Mapper>();
+    private static final String ATTRIBUTE = MapperLocator.class.getName() + ".mapper";
+
+    @Override
+    public void contextInitialized(final ServletContextEvent servletContextEvent) {
+        final Mapper build = newMapper();
+        MAPPER_BY_LOADER.put(servletContextEvent.getServletContext().getClassLoader(), build);
+        servletContextEvent.getServletContext().setAttribute(ATTRIBUTE, build);
+    }
+
+    @Override
+    public void contextDestroyed(final ServletContextEvent servletContextEvent) {
+        MAPPER_BY_LOADER.remove(servletContextEvent.getServletContext().getClassLoader());
+    }
+
+    public static Mapper locate() {
+        ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        if (loader == null) {
+            loader = MapperLocator.class.getClassLoader();
+        }
+        final Mapper mapper = MAPPER_BY_LOADER.get(loader);
+        if (mapper == null) {
+            return newMapper();
+        }
+        return mapper;
+    }
+
+    private static Mapper newMapper() {
+        return new MapperBuilder().build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrArrayDecoder.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrArrayDecoder.java b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrArrayDecoder.java
new file mode 100644
index 0000000..284b036
--- /dev/null
+++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrArrayDecoder.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.jsr;
+
+import org.apache.johnzon.websocket.internal.jsr.JsrDecoder;
+
+import javax.json.JsonArray;
+import javax.json.JsonReader;
+
+public class JsrArrayDecoder extends JsrDecoder<JsonArray> {
+    @Override
+    protected JsonArray doRead(JsonReader jsonReader) {
+        return jsonReader.readArray();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrArrayEncoder.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrArrayEncoder.java b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrArrayEncoder.java
new file mode 100644
index 0000000..9eb02f8
--- /dev/null
+++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrArrayEncoder.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.jsr;
+
+import org.apache.johnzon.websocket.internal.jsr.JsrEncoder;
+
+import javax.json.JsonArray;
+import javax.json.JsonWriter;
+
+public class JsrArrayEncoder extends JsrEncoder<JsonArray> {
+    @Override
+    protected void doWrite(final JsonWriter writer, final JsonArray array) {
+        writer.writeArray(array);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrObjectDecoder.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrObjectDecoder.java b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrObjectDecoder.java
new file mode 100644
index 0000000..c63bfaa
--- /dev/null
+++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrObjectDecoder.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.jsr;
+
+import org.apache.johnzon.websocket.internal.jsr.JsrDecoder;
+
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import javax.json.JsonReaderFactory;
+
+public class JsrObjectDecoder extends JsrDecoder<JsonObject> {
+    private JsonReaderFactory factory;
+
+    @Override
+    protected JsonObject doRead(final JsonReader jsonReader) {
+        return jsonReader.readObject();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrObjectEncoder.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrObjectEncoder.java b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrObjectEncoder.java
new file mode 100644
index 0000000..b5cd180
--- /dev/null
+++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrObjectEncoder.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.jsr;
+
+import org.apache.johnzon.websocket.internal.jsr.JsrEncoder;
+
+import javax.json.JsonObject;
+import javax.json.JsonWriter;
+
+public class JsrObjectEncoder extends JsrEncoder<JsonObject> {
+    @Override
+    protected void doWrite(final JsonWriter writer, final JsonObject jsonObject) {
+        writer.writeObject(jsonObject);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrStructureDecoder.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrStructureDecoder.java b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrStructureDecoder.java
new file mode 100644
index 0000000..f4ad438
--- /dev/null
+++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrStructureDecoder.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.jsr;
+
+import org.apache.johnzon.websocket.internal.jsr.JsrDecoder;
+
+import javax.json.JsonReader;
+import javax.json.JsonReaderFactory;
+import javax.json.JsonStructure;
+
+public class JsrStructureDecoder extends JsrDecoder<JsonStructure> {
+    private JsonReaderFactory factory;
+
+    @Override
+    protected JsonStructure doRead(final JsonReader jsonReader) {
+        return jsonReader.read();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrStructureEncoder.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrStructureEncoder.java b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrStructureEncoder.java
new file mode 100644
index 0000000..69169f3
--- /dev/null
+++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsr/JsrStructureEncoder.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.jsr;
+
+import org.apache.johnzon.websocket.internal.jsr.JsrEncoder;
+
+import javax.json.JsonStructure;
+import javax.json.JsonWriter;
+
+public class JsrStructureEncoder extends JsrEncoder<JsonStructure> {
+    @Override
+    protected void doWrite(final JsonWriter writer, final JsonStructure structure) {
+        writer.write(structure);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextDecoder.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextDecoder.java b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextDecoder.java
new file mode 100644
index 0000000..4530966
--- /dev/null
+++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextDecoder.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.mapper;
+
+import org.apache.johnzon.mapper.Mapper;
+import org.apache.johnzon.websocket.internal.mapper.MapperLocator;
+
+import java.io.Reader;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import javax.websocket.DecodeException;
+import javax.websocket.Decoder;
+import javax.websocket.EndpointConfig;
+import javax.websocket.OnMessage;
+import javax.websocket.Session;
+import javax.websocket.server.PathParam;
+import javax.websocket.server.ServerEndpointConfig;
+
+public class JohnzonTextDecoder implements Decoder.TextStream<Object> {
+    protected Mapper mapper;
+    protected Type type;
+
+    public JohnzonTextDecoder() {
+        // no-op
+    }
+
+    // for client side no way to guess the type so let the user provide it easily
+    public JohnzonTextDecoder(final Type type) {
+        this(null, type);
+    }
+
+    public JohnzonTextDecoder(final Mapper mapper, final Type type) {
+        this.mapper = mapper;
+        this.type = type;
+    }
+
+    @Override
+    public Object decode(final Reader stream) throws DecodeException {
+        return mapper.readObject(stream, type);
+    }
+
+    @Override
+    public void init(final EndpointConfig endpointConfig) {
+        if (mapper == null) {
+            mapper = MapperLocator.locate();
+        }
+        if (type != null) {
+            return;
+        }
+
+        if (ServerEndpointConfig.class.isInstance(endpointConfig)) {
+            final Class<?> endpointClass = ServerEndpointConfig.class.cast(endpointConfig).getEndpointClass();
+            for (final Method m : endpointClass.getMethods()) {
+                if (Object.class == m.getDeclaringClass()) {
+                    continue;
+                }
+                if (m.getAnnotation(OnMessage.class) != null) {
+                    final Type[] genericParameterTypes = m.getGenericParameterTypes();
+                    for (int i = 0; i < genericParameterTypes.length; i++) {
+                        if (genericParameterTypes[i] == Session.class) {
+                            continue;
+                        }
+                        boolean param = false;
+                        for (final Annotation a : m.getParameterAnnotations()[i]) {
+                            if (PathParam.class == a.annotationType()) {
+                                param = true;
+                                break;
+                            }
+                        }
+                        if (!param) {
+                            this.type = genericParameterTypes[i];
+                            break;
+                        }
+                    }
+                    break;
+                }
+            }
+            if (type == null) {
+                throw new IllegalArgumentException("didn't find @OnMessage in " + endpointClass);
+            }
+        } else {
+            type = Type.class.cast(endpointConfig.getUserProperties().get("johnzon.websocket.message.type"));
+            if (type == null) {
+                throw new IllegalArgumentException("didn't find johnzon.websocket.message.type");
+            }
+        }
+    }
+
+    @Override
+    public void destroy() {
+        // no-op
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextEncoder.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextEncoder.java b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextEncoder.java
new file mode 100644
index 0000000..964c3b5
--- /dev/null
+++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextEncoder.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.mapper;
+
+import org.apache.johnzon.mapper.Mapper;
+import org.apache.johnzon.websocket.internal.mapper.MapperLocator;
+
+import java.io.IOException;
+import java.io.Writer;
+import javax.websocket.EncodeException;
+import javax.websocket.Encoder;
+import javax.websocket.EndpointConfig;
+
+public class JohnzonTextEncoder implements Encoder.TextStream<Object> {
+    private Mapper mapper;
+
+    @Override
+    public void init(final EndpointConfig endpointConfig) {
+        mapper = MapperLocator.locate();
+    }
+
+    @Override
+    public void destroy() {
+        // no-op
+    }
+
+    @Override
+    public void encode(final Object object, final Writer writer) throws EncodeException, IOException {
+        mapper.writeObject(object, writer);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/JsrCodecTest.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/JsrCodecTest.java b/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/JsrCodecTest.java
new file mode 100644
index 0000000..9fc860e
--- /dev/null
+++ b/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/JsrCodecTest.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket;
+
+import org.apache.johnzon.core.JsonProviderImpl;
+import org.apache.johnzon.websocket.endpoint.JsrClientEndpointImpl;
+import org.apache.johnzon.websocket.endpoint.JsrServerEndpointImpl;
+import org.apache.johnzon.websocket.endpoint.Message;
+import org.apache.johnzon.websocket.endpoint.ServerReport;
+import org.apache.johnzon.websocket.internal.jsr.FactoryLocator;
+import org.apache.johnzon.websocket.internal.jsr.JsrDecoder;
+import org.apache.johnzon.websocket.internal.jsr.JsrEncoder;
+import org.apache.johnzon.websocket.jsr.JsrObjectDecoder;
+import org.apache.johnzon.websocket.jsr.JsrObjectEncoder;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.URI;
+import java.net.URL;
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.websocket.CloseReason;
+import javax.websocket.ContainerProvider;
+import javax.websocket.Session;
+import javax.websocket.WebSocketContainer;
+
+import static org.apache.openejb.loader.JarLocation.jarLocation;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+@RunWith(Arquillian.class)
+public class JsrCodecTest {
+    @Deployment(testable = false)
+    public static WebArchive war() {
+        return ShrinkWrap.create(WebArchive.class, "jsr-codec.war")
+                .addClasses(JsrServerEndpointImpl.class, ServerReport.class, Message.class /* for report endpoint */)
+                .addAsLibrary(
+                        ShrinkWrap.create(JavaArchive.class, "johnzon-websocket.jar")
+                                .addClasses(FactoryLocator.class, JsrDecoder.class, JsrEncoder.class, JsrObjectDecoder.class, JsrObjectEncoder.class))
+                .addAsLibraries(
+                        jarLocation(Json.class),
+                        jarLocation(JsonProviderImpl.class));
+    }
+
+    @ArquillianResource
+    private URL url;
+
+    @Test
+    public void codec() throws Exception {
+        JsrClientEndpointImpl.MESSAGES.clear();
+
+        final WebSocketContainer container = ContainerProvider.getWebSocketContainer();
+        final Session session = container.connectToServer(
+                JsrClientEndpointImpl.class,
+                new URI("ws://localhost:" + url.getPort() + url.getPath() + "jsrserver"));
+
+        session.getBasicRemote().sendObject(Json.createObjectBuilder().add("value", "jsr@client").build());
+
+        JsrClientEndpointImpl.SEMAPHORE.acquire();
+
+        // it does wait for the server, using same jaxrs provider to match format, it uses jettison which is weird but we don't care for that part of test
+        final JsonObject serverMessage = Json.createReader(new URL(url.toExternalForm() + "report/jsr").openStream()).readObject();
+
+        session.close(new CloseReason(CloseReason.CloseCodes.GOING_AWAY, "bye"));
+
+        assertNotNull(serverMessage);
+        assertEquals("jsr@client", serverMessage.getString("value"));
+        assertEquals(1, JsrClientEndpointImpl.MESSAGES.size());
+        assertEquals("jsr@server", JsrClientEndpointImpl.MESSAGES.iterator().next().getString("value"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/MapperCodecTest.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/MapperCodecTest.java b/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/MapperCodecTest.java
new file mode 100644
index 0000000..1212941
--- /dev/null
+++ b/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/MapperCodecTest.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket;
+
+import org.apache.johnzon.core.JsonProviderImpl;
+import org.apache.johnzon.mapper.Mapper;
+import org.apache.johnzon.mapper.MapperBuilder;
+import org.apache.johnzon.websocket.endpoint.ClientEndpointImpl;
+import org.apache.johnzon.websocket.endpoint.Message;
+import org.apache.johnzon.websocket.endpoint.ServerEndpointImpl;
+import org.apache.johnzon.websocket.endpoint.ServerReport;
+import org.apache.johnzon.websocket.internal.mapper.MapperLocator;
+import org.apache.johnzon.websocket.mapper.JohnzonTextDecoder;
+import org.apache.johnzon.websocket.mapper.JohnzonTextEncoder;
+import org.apache.openejb.arquillian.common.IO;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.URI;
+import java.net.URL;
+import javax.json.Json;
+import javax.websocket.CloseReason;
+import javax.websocket.ContainerProvider;
+import javax.websocket.Session;
+import javax.websocket.WebSocketContainer;
+
+import static org.apache.openejb.loader.JarLocation.jarLocation;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+@RunWith(Arquillian.class)
+public class MapperCodecTest {
+    @Deployment(testable = false)
+    public static WebArchive war() {
+        return ShrinkWrap.create(WebArchive.class, "codec.war")
+                .addClasses(ServerEndpointImpl.class, ServerReport.class, Message.class)
+                .addAsLibrary(
+                        ShrinkWrap.create(JavaArchive.class, "johnzon-websocket.jar")
+                            .addClasses(MapperLocator.class, JohnzonTextDecoder.class, JohnzonTextEncoder.class))
+                .addAsLibraries(
+                        jarLocation(Json.class),
+                        jarLocation(JsonProviderImpl.class),
+                        jarLocation(Mapper.class));
+    }
+
+    @ArquillianResource
+    private URL url;
+
+    @Test
+    public void codec() throws Exception {
+        ClientEndpointImpl.MESSAGES.clear();
+        ClientEndpointImpl.SEMAPHORE.acquire(ClientEndpointImpl.SEMAPHORE.availablePermits());
+
+        final WebSocketContainer container = ContainerProvider.getWebSocketContainer();
+        final Session session = container.connectToServer(
+                ClientEndpointImpl.class,
+                new URI("ws://localhost:" + url.getPort() + url.getPath() + "server"));
+
+        session.getBasicRemote().sendObject(new Message("client"));
+
+        ClientEndpointImpl.SEMAPHORE.acquire();
+
+        // it does wait for the server, using same jaxrs provider to match format, it uses jettison which is weird but we don't care for that part of test
+        final Message serverMessage = new MapperBuilder().build().readObject(IO.slurp(new URL(url.toExternalForm() + "report/annotation")), Message.class);
+
+        session.close(new CloseReason(CloseReason.CloseCodes.GOING_AWAY, "bye"));
+
+        assertNotNull(serverMessage);
+        assertEquals("client", serverMessage.getValue());
+        assertEquals(1, ClientEndpointImpl.MESSAGES.size());
+        assertEquals("server", ClientEndpointImpl.MESSAGES.iterator().next().getValue());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/ClientEndpointImpl.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/ClientEndpointImpl.java b/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/ClientEndpointImpl.java
new file mode 100644
index 0000000..10020ad
--- /dev/null
+++ b/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/ClientEndpointImpl.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.endpoint;
+
+import org.apache.johnzon.websocket.mapper.JohnzonTextDecoder;
+import org.apache.johnzon.websocket.mapper.JohnzonTextEncoder;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import javax.websocket.ClientEndpoint;
+import javax.websocket.EndpointConfig;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+
+@ClientEndpoint(encoders = JohnzonTextEncoder.class, decoders = ClientEndpointImpl.MessageDecoder.class)
+public class ClientEndpointImpl {
+    public static final List<Message> MESSAGES = new LinkedList<Message>();
+    public static final Semaphore SEMAPHORE = new Semaphore(0);
+
+    @OnOpen
+    public void init(final EndpointConfig config) {
+
+    }
+
+    @OnMessage
+    public synchronized void on(final Message message) {
+        MESSAGES.add(message);
+        SEMAPHORE.release();
+    }
+
+    public static class MessageDecoder extends JohnzonTextDecoder {
+        public MessageDecoder() {
+            type = Message.class;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/JsrClientEndpointImpl.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/JsrClientEndpointImpl.java b/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/JsrClientEndpointImpl.java
new file mode 100644
index 0000000..644585e
--- /dev/null
+++ b/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/JsrClientEndpointImpl.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.endpoint;
+
+import org.apache.johnzon.websocket.jsr.JsrObjectDecoder;
+import org.apache.johnzon.websocket.jsr.JsrObjectEncoder;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import javax.json.JsonObject;
+import javax.websocket.ClientEndpoint;
+import javax.websocket.OnMessage;
+
+@ClientEndpoint(encoders = JsrObjectEncoder.class, decoders = JsrObjectDecoder.class)
+public class JsrClientEndpointImpl {
+    public static final List<JsonObject> MESSAGES = new LinkedList<JsonObject>();
+    public static final Semaphore SEMAPHORE = new Semaphore(0);
+
+    @OnMessage
+    public synchronized void on(final JsonObject message) {
+        MESSAGES.add(message);
+        SEMAPHORE.release();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/JsrServerEndpointImpl.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/JsrServerEndpointImpl.java b/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/JsrServerEndpointImpl.java
new file mode 100644
index 0000000..a442259
--- /dev/null
+++ b/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/JsrServerEndpointImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.endpoint;
+
+import org.apache.johnzon.websocket.jsr.JsrObjectDecoder;
+import org.apache.johnzon.websocket.jsr.JsrObjectEncoder;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.websocket.EncodeException;
+import javax.websocket.OnMessage;
+import javax.websocket.Session;
+import javax.websocket.server.ServerEndpoint;
+
+@ServerEndpoint(value = "/jsrserver", encoders = JsrObjectEncoder.class, decoders = JsrObjectDecoder.class)
+public class JsrServerEndpointImpl {
+    public static final List<JsonObject> MESSAGES = new LinkedList<JsonObject>();
+    public static final Semaphore SEMAPHORE = new Semaphore(0);
+
+    @OnMessage
+    public synchronized void on(final Session session, final JsonObject message) throws IOException, EncodeException {
+        MESSAGES.add(message);
+        SEMAPHORE.release();
+
+        final JsonObjectBuilder builder = Json.createBuilderFactory(Collections.<String, Object>emptyMap()).createObjectBuilder();
+        session.getBasicRemote().sendObject(builder.add("value", "jsr@server").build());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/Message.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/Message.java b/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/Message.java
new file mode 100644
index 0000000..99f2d24
--- /dev/null
+++ b/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/Message.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.endpoint;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement // old tomee default json provider (pre-johnzon erea) was using jaxb
+public class Message {
+    private String value;
+
+    public Message() {
+        // no-op
+    }
+
+    public Message(final String msg) {
+        this.value = msg;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(final String value) {
+        this.value = value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/ServerEndpointImpl.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/ServerEndpointImpl.java b/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/ServerEndpointImpl.java
new file mode 100644
index 0000000..ae42c88
--- /dev/null
+++ b/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/ServerEndpointImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.endpoint;
+
+import org.apache.johnzon.websocket.mapper.JohnzonTextDecoder;
+import org.apache.johnzon.websocket.mapper.JohnzonTextEncoder;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import javax.websocket.EncodeException;
+import javax.websocket.OnMessage;
+import javax.websocket.Session;
+import javax.websocket.server.ServerEndpoint;
+
+@ServerEndpoint(value = "/server", encoders = JohnzonTextEncoder.class, decoders = JohnzonTextDecoder.class)
+public class ServerEndpointImpl {
+    public static final List<Message> MESSAGES = new LinkedList<Message>();
+    public static final Semaphore SEMAPHORE = new Semaphore(0);
+
+    @OnMessage
+    public synchronized void on(final Session session, final Message message) throws IOException, EncodeException {
+        MESSAGES.add(message);
+        SEMAPHORE.release();
+        session.getBasicRemote().sendObject(new Message("server"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/ServerReport.java
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/ServerReport.java b/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/ServerReport.java
new file mode 100644
index 0000000..3fc211b
--- /dev/null
+++ b/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/endpoint/ServerReport.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.websocket.endpoint;
+
+import org.apache.johnzon.mapper.MapperBuilder;
+
+import java.io.StringWriter;
+import java.util.concurrent.TimeUnit;
+import javax.json.Json;
+import javax.json.JsonWriter;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("report")
+@Produces(MediaType.APPLICATION_JSON)
+public class ServerReport {
+    @GET
+    @Path("annotation")
+    public String amessage() {
+        try {
+            if (!ServerEndpointImpl.SEMAPHORE.tryAcquire(1, TimeUnit.MINUTES)) {
+                throw new IllegalStateException("acquire failed");
+            }
+        } catch (final InterruptedException e) {
+            Thread.interrupted();
+            return null;
+        }
+
+        // don't setup (+dependency) for just this method the mapper jaxrs provider
+        return new MapperBuilder().build().writeObjectAsString(ServerEndpointImpl.MESSAGES.iterator().next());
+    }
+
+    @GET
+    @Path("jsr")
+    @Produces(MediaType.APPLICATION_JSON)
+    public String pmessage() {
+        try {
+            if (!JsrServerEndpointImpl.SEMAPHORE.tryAcquire(1, TimeUnit.MINUTES)) {
+                throw new IllegalStateException("acquire failed");
+            }
+        } catch (final InterruptedException e) {
+            Thread.interrupted();
+            return null;
+        }
+
+        // don't setup (+dependency) for just this method the jsr jaxrs provider
+        final StringWriter output = new StringWriter();
+        final JsonWriter writer = Json.createWriter(output);
+        writer.write(JsrServerEndpointImpl.MESSAGES.iterator().next());
+        writer.close();
+        return output.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/johnzon-websocket/src/test/resources/arquillian.xml
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/test/resources/arquillian.xml b/johnzon-websocket/src/test/resources/arquillian.xml
new file mode 100644
index 0000000..c86d7a3
--- /dev/null
+++ b/johnzon-websocket/src/test/resources/arquillian.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<arquillian xmlns="http://jboss.org/schema/arquillian"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="
+              http://jboss.org/schema/arquillian
+              http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
+  <container qualifier="tomee" default="true">
+    <configuration>
+      <property name="classifier">jaxrs</property>
+      <property name="httpsPort">-1</property>
+      <property name="httpPort">-1</property>
+      <property name="stopPort">-1</property>
+      <property name="ajpPort">-1</property>
+      <property name="simpleLog">true</property>
+      <property name="cleanOnStartUp">true</property>
+      <property name="dir">target/apache-tomee-remote</property>
+      <property name="appWorkingDir">target/arquillian-test-working-dir</property>
+    </configuration>
+  </container>
+</arquillian>

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/29a79edb/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index a848fc2..0aef897 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,6 +51,7 @@
     <module>johnzon-core</module>
     <module>johnzon-mapper</module>
     <module>johnzon-jaxrs</module>
+    <module>johnzon-websocket</module>
   </modules>
 
   <dependencies>