This is an automated email from the ASF dual-hosted git repository. rmannibucau pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/johnzon.git
The following commit(s) were added to refs/heads/master by this push: new 73eb0fb [JOHNZON-340] add JSON-B support in websocket module 73eb0fb is described below commit 73eb0fbaac15d837432ca6f6531c5e811ef918b1 Author: Romain Manni-Bucau <rmannibu...@gmail.com> AuthorDate: Thu Apr 22 10:08:15 2021 +0200 [JOHNZON-340] add JSON-B support in websocket module --- johnzon-websocket/pom.xml | 14 ++++ .../TypeAwareDecoder.java} | 43 ++--------- .../lazy/LazySupplier.java} | 38 +++++----- .../websocket/internal/mapper/MapperLocator.java | 42 ++--------- .../internal/mapper/MapperLocatorDelegate.java | 86 ++++++++++++++++++++++ .../servlet/IgnoreIfMissing.java} | 37 +++++----- .../JsonbLocator.java} | 31 ++------ .../websocket/jsonb/JsonbLocatorDelegate.java | 83 +++++++++++++++++++++ .../johnzon/websocket/jsonb/JsonbTextDecoder.java | 70 ++++++++++++++++++ .../JsonbTextEncoder.java} | 24 +++--- .../websocket/mapper/JohnzonTextDecoder.java | 10 +-- .../websocket/mapper/JohnzonTextEncoder.java | 6 +- .../apache/johnzon/websocket/MapperCodecTest.java | 4 +- src/site/markdown/index.md | 17 +++++ 14 files changed, 354 insertions(+), 151 deletions(-) diff --git a/johnzon-websocket/pom.xml b/johnzon-websocket/pom.xml index c73c2f1..7568633 100644 --- a/johnzon-websocket/pom.xml +++ b/johnzon-websocket/pom.xml @@ -49,9 +49,23 @@ </dependency> <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-jsonb_1.0_spec</artifactId> + <scope>provided</scope> + </dependency> + + <dependency> <groupId>org.apache.johnzon</groupId> <artifactId>johnzon-mapper</artifactId> <version>${project.version}</version> + <scope>provided</scope> + <optional>true</optional> + </dependency> + <dependency> + <groupId>org.apache.johnzon</groupId> + <artifactId>johnzon-jsonb</artifactId> + <version>${project.version}</version> + <scope>test</scope> </dependency> <dependency> 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/internal/TypeAwareDecoder.java similarity index 74% copy from johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextDecoder.java copy to johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/TypeAwareDecoder.java index 4530966..0e92215 100644 --- a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextDecoder.java +++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/TypeAwareDecoder.java @@ -16,51 +16,29 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.johnzon.websocket.mapper; +package org.apache.johnzon.websocket.internal; -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; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Type; -public class JohnzonTextDecoder implements Decoder.TextStream<Object> { - protected Mapper mapper; +public abstract class TypeAwareDecoder { protected Type type; - public JohnzonTextDecoder() { + public TypeAwareDecoder() { // 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; + public TypeAwareDecoder(final Type type) { 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(); - } + protected void init(final EndpointConfig endpointConfig) { if (type != null) { return; } @@ -102,9 +80,4 @@ public class JohnzonTextDecoder implements Decoder.TextStream<Object> { } } } - - @Override - public void destroy() { - // no-op - } } 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/internal/lazy/LazySupplier.java similarity index 53% copy from johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextEncoder.java copy to johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/lazy/LazySupplier.java index 964c3b5..e8c95e7 100644 --- a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextEncoder.java +++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/lazy/LazySupplier.java @@ -16,32 +16,32 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.johnzon.websocket.mapper; +package org.apache.johnzon.websocket.internal.lazy; -import org.apache.johnzon.mapper.Mapper; -import org.apache.johnzon.websocket.internal.mapper.MapperLocator; +import java.util.function.Supplier; -import java.io.IOException; -import java.io.Writer; -import javax.websocket.EncodeException; -import javax.websocket.Encoder; -import javax.websocket.EndpointConfig; +public class LazySupplier<T> implements Supplier<T> { + private Supplier<T> delegate; + private volatile T instance; -public class JohnzonTextEncoder implements Encoder.TextStream<Object> { - private Mapper mapper; - - @Override - public void init(final EndpointConfig endpointConfig) { - mapper = MapperLocator.locate(); + public LazySupplier(final Supplier<T> provider) { + this.delegate = provider; } @Override - public void destroy() { - // no-op + public T get() { + if (instance == null) { + synchronized (this) { + if (instance == null) { + instance = delegate.get(); + delegate = null; + } + } + } + return instance; } - @Override - public void encode(final Object object, final Writer writer) throws EncodeException, IOException { - mapper.writeObject(object, writer); + public T getInstance() { + return instance; } } 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 index 9145694..6596437 100644 --- 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 @@ -18,45 +18,17 @@ */ package org.apache.johnzon.websocket.internal.mapper; -import org.apache.johnzon.mapper.Mapper; -import org.apache.johnzon.mapper.MapperBuilder; +import org.apache.johnzon.websocket.internal.servlet.IgnoreIfMissing; -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; +@WebListener // since people move to json-b we make this init lazy +public class MapperLocator extends IgnoreIfMissing { + public MapperLocator() { + super(() -> new MapperLocatorDelegate()); } - private static Mapper newMapper() { - return new MapperBuilder().build(); + public static Object locate() { + return MapperLocatorDelegate.locate(); } } diff --git a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/mapper/MapperLocatorDelegate.java b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/mapper/MapperLocatorDelegate.java new file mode 100644 index 0000000..48fc30d --- /dev/null +++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/mapper/MapperLocatorDelegate.java @@ -0,0 +1,86 @@ +/* + * 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 org.apache.johnzon.websocket.internal.lazy.LazySupplier; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; + +import static java.util.Optional.ofNullable; + +public class MapperLocatorDelegate implements ServletContextListener { + private static final Map<ClassLoader, Supplier<Mapper>> MAPPER_BY_LOADER = new ConcurrentHashMap<ClassLoader, Supplier<Mapper>>(); + private static final String ATTRIBUTE = MapperLocator.class.getName() + ".mapper"; + + @Override + public void contextInitialized(final ServletContextEvent servletContextEvent) { + final ServletContext servletContext = servletContextEvent.getServletContext(); + final Supplier<Mapper> supplier = ofNullable(servletContext.getAttribute(ATTRIBUTE)) + .map(it -> (Supplier<Mapper>) it) + .orElseGet(() -> { + final LazySupplier<Mapper> lazySupplier = new LazySupplier<>(MapperLocatorDelegate::newMapper); + servletContext.setAttribute(ATTRIBUTE, lazySupplier); + return lazySupplier; + }); + MAPPER_BY_LOADER.put(servletContext.getClassLoader(), supplier); + } + + @Override + public void contextDestroyed(final ServletContextEvent servletContextEvent) { + final Supplier<Mapper> supplier = MAPPER_BY_LOADER.remove(servletContextEvent.getServletContext().getClassLoader()); + if (LazySupplier.class.isInstance(supplier)) { + final Object mapper = LazySupplier.class.cast(supplier).getInstance(); + if (mapper != null) { + Mapper.class.cast(mapper).close(); + } + } + } + + public static Mapper locate() { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + if (loader == null) { + loader = MapperLocatorDelegate.class.getClassLoader(); + } + Supplier<Mapper> mapper = MAPPER_BY_LOADER.get(loader); + if (mapper == null) { + synchronized (MAPPER_BY_LOADER) { + mapper = MAPPER_BY_LOADER.get(loader); + if (mapper != null) { + return mapper.get(); + } + final Mapper instance = newMapper(); + mapper = () -> instance; + MAPPER_BY_LOADER.put(loader, mapper); + return mapper.get(); + } + } + return mapper.get(); + } + + private static Mapper newMapper() { + return new MapperBuilder().build(); + } +} 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/internal/servlet/IgnoreIfMissing.java similarity index 51% copy from johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextEncoder.java copy to johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/servlet/IgnoreIfMissing.java index 964c3b5..f91344e 100644 --- a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextEncoder.java +++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/internal/servlet/IgnoreIfMissing.java @@ -16,32 +16,33 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.johnzon.websocket.mapper; +package org.apache.johnzon.websocket.internal.servlet; -import org.apache.johnzon.mapper.Mapper; -import org.apache.johnzon.websocket.internal.mapper.MapperLocator; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import java.util.function.Supplier; -import java.io.IOException; -import java.io.Writer; -import javax.websocket.EncodeException; -import javax.websocket.Encoder; -import javax.websocket.EndpointConfig; +public class IgnoreIfMissing implements ServletContextListener { + private final Supplier<ServletContextListener> delegate; + private boolean skipped; -public class JohnzonTextEncoder implements Encoder.TextStream<Object> { - private Mapper mapper; - - @Override - public void init(final EndpointConfig endpointConfig) { - mapper = MapperLocator.locate(); + public IgnoreIfMissing(final Supplier<ServletContextListener> delegate) { + this.delegate = delegate; } @Override - public void destroy() { - // no-op + public void contextInitialized(final ServletContextEvent sce) { + try { + delegate.get().contextInitialized(sce); + } catch (final Error | RuntimeException re) { + skipped = true; + } } @Override - public void encode(final Object object, final Writer writer) throws EncodeException, IOException { - mapper.writeObject(object, writer); + public void contextDestroyed(final ServletContextEvent sce) { + if (!skipped) { + delegate.get().contextDestroyed(sce); + } } } 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/jsonb/JsonbLocator.java similarity index 51% copy from johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextEncoder.java copy to johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsonb/JsonbLocator.java index 964c3b5..d84490d 100644 --- a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextEncoder.java +++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsonb/JsonbLocator.java @@ -16,32 +16,15 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.johnzon.websocket.mapper; +package org.apache.johnzon.websocket.jsonb; -import org.apache.johnzon.mapper.Mapper; -import org.apache.johnzon.websocket.internal.mapper.MapperLocator; +import org.apache.johnzon.websocket.internal.servlet.IgnoreIfMissing; -import java.io.IOException; -import java.io.Writer; -import javax.websocket.EncodeException; -import javax.websocket.Encoder; -import javax.websocket.EndpointConfig; +import javax.servlet.annotation.WebListener; -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); +@WebListener +public class JsonbLocator extends IgnoreIfMissing { + public JsonbLocator() { + super(() -> new JsonbLocatorDelegate()); } } diff --git a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsonb/JsonbLocatorDelegate.java b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsonb/JsonbLocatorDelegate.java new file mode 100644 index 0000000..3e1032a --- /dev/null +++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsonb/JsonbLocatorDelegate.java @@ -0,0 +1,83 @@ +/* + * 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.jsonb; + +import javax.json.bind.Jsonb; +import javax.json.bind.JsonbBuilder; +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static java.util.Optional.ofNullable; + +public class JsonbLocatorDelegate implements ServletContextListener { + private static final Map<ClassLoader, Jsonb> BY_LOADER = new ConcurrentHashMap<>(); + private static final String ATTRIBUTE = JsonbLocator.class.getName() + ".jsonb"; + + @Override + public void contextInitialized(final ServletContextEvent servletContextEvent) { + final ServletContext servletContext = servletContextEvent.getServletContext(); + final Jsonb instance = ofNullable(servletContext.getAttribute(ATTRIBUTE)) + .map(Jsonb.class::cast) + .orElseGet(() -> { + final Jsonb jsonb = newInstance(); + servletContext.setAttribute(ATTRIBUTE, jsonb); + return jsonb; + }); + BY_LOADER.put(servletContext.getClassLoader(), instance); + } + + @Override + public void contextDestroyed(final ServletContextEvent servletContextEvent) { + final Jsonb instance = BY_LOADER.remove(servletContextEvent.getServletContext().getClassLoader()); + if (instance != null) { + try { + instance.close(); + } catch (final Exception e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + } + + public static Jsonb locate() { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + if (loader == null) { + loader = JsonbLocatorDelegate.class.getClassLoader(); + } + Jsonb jsonb = BY_LOADER.get(loader); + if (jsonb == null) { + synchronized (BY_LOADER) { + jsonb = BY_LOADER.get(loader); + if (jsonb != null) { + return jsonb; + } + jsonb = newInstance(); + BY_LOADER.put(loader, jsonb); + return jsonb; + } + } + return jsonb; + } + + private static Jsonb newInstance() { + return JsonbBuilder.create(); + } +} diff --git a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsonb/JsonbTextDecoder.java b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsonb/JsonbTextDecoder.java new file mode 100644 index 0000000..c010e89 --- /dev/null +++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsonb/JsonbTextDecoder.java @@ -0,0 +1,70 @@ +/* + * 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.jsonb; + +import org.apache.johnzon.websocket.internal.TypeAwareDecoder; + +import javax.json.bind.Jsonb; +import javax.json.bind.JsonbException; +import javax.websocket.DecodeException; +import javax.websocket.Decoder; +import javax.websocket.EndpointConfig; +import java.io.Reader; +import java.lang.reflect.Type; + +public class JsonbTextDecoder extends TypeAwareDecoder implements Decoder.TextStream<Object> { + protected Jsonb mapper; + protected Type type; + + public JsonbTextDecoder() { + // no-op + } + + // for client side no way to guess the type so let the user provide it easily + public JsonbTextDecoder(final Type type) { + this(null, type); + } + + public JsonbTextDecoder(final Jsonb jsonb, final Type type) { + super(type); + this.mapper = jsonb; + } + + @Override + public Object decode(final Reader stream) throws DecodeException { + try { + return mapper.fromJson(stream, type); + } catch (final JsonbException je) { + throw new DecodeException("", je.getMessage(), je); + } + } + + @Override + public void init(final EndpointConfig endpointConfig) { + if (mapper == null) { + mapper = JsonbLocatorDelegate.locate(); + } + super.init(endpointConfig); + } + + @Override + public void destroy() { + // no-op + } +} 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/jsonb/JsonbTextEncoder.java similarity index 71% copy from johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextEncoder.java copy to johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsonb/JsonbTextEncoder.java index 964c3b5..bf1873c 100644 --- a/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/mapper/JohnzonTextEncoder.java +++ b/johnzon-websocket/src/main/java/org/apache/johnzon/websocket/jsonb/JsonbTextEncoder.java @@ -16,23 +16,21 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.johnzon.websocket.mapper; +package org.apache.johnzon.websocket.jsonb; -import org.apache.johnzon.mapper.Mapper; -import org.apache.johnzon.websocket.internal.mapper.MapperLocator; - -import java.io.IOException; -import java.io.Writer; +import javax.json.bind.Jsonb; +import javax.json.bind.JsonbException; import javax.websocket.EncodeException; import javax.websocket.Encoder; import javax.websocket.EndpointConfig; +import java.io.Writer; -public class JohnzonTextEncoder implements Encoder.TextStream<Object> { - private Mapper mapper; +public class JsonbTextEncoder implements Encoder.TextStream<Object> { + private Jsonb jsonb; @Override public void init(final EndpointConfig endpointConfig) { - mapper = MapperLocator.locate(); + jsonb = JsonbLocatorDelegate.locate(); } @Override @@ -41,7 +39,11 @@ public class JohnzonTextEncoder implements Encoder.TextStream<Object> { } @Override - public void encode(final Object object, final Writer writer) throws EncodeException, IOException { - mapper.writeObject(object, writer); + public void encode(final Object object, final Writer writer) throws EncodeException { + try { + jsonb.toJson(object, writer); + } catch (final JsonbException je) { + throw new EncodeException(object, je.getMessage(), je); + } } } 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 index 4530966..60c27fa 100644 --- 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 @@ -21,10 +21,6 @@ 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; @@ -32,6 +28,10 @@ import javax.websocket.OnMessage; import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpointConfig; +import java.io.Reader; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Type; public class JohnzonTextDecoder implements Decoder.TextStream<Object> { protected Mapper mapper; @@ -59,7 +59,7 @@ public class JohnzonTextDecoder implements Decoder.TextStream<Object> { @Override public void init(final EndpointConfig endpointConfig) { if (mapper == null) { - mapper = MapperLocator.locate(); + mapper = Mapper.class.cast(MapperLocator.locate()); } if (type != null) { return; 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 index 964c3b5..015daa9 100644 --- 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 @@ -21,18 +21,18 @@ 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; +import java.io.IOException; +import java.io.Writer; public class JohnzonTextEncoder implements Encoder.TextStream<Object> { private Mapper mapper; @Override public void init(final EndpointConfig endpointConfig) { - mapper = MapperLocator.locate(); + mapper = Mapper.class.cast(MapperLocator.locate()); } @Override 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 index 9b2770c..2dcc209 100644 --- a/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/MapperCodecTest.java +++ b/johnzon-websocket/src/test/java/org/apache/johnzon/websocket/MapperCodecTest.java @@ -26,6 +26,8 @@ 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.internal.mapper.MapperLocatorDelegate; +import org.apache.johnzon.websocket.internal.servlet.IgnoreIfMissing; import org.apache.johnzon.websocket.mapper.JohnzonTextDecoder; import org.apache.johnzon.websocket.mapper.JohnzonTextEncoder; import org.apache.openejb.arquillian.common.IO; @@ -58,7 +60,7 @@ public class MapperCodecTest { .addClasses(ServerEndpointImpl.class, ServerReport.class, Message.class) .addAsLibrary( ShrinkWrap.create(JavaArchive.class, "johnzon-websocket.jar") - .addClasses(MapperLocator.class, JohnzonTextDecoder.class, JohnzonTextEncoder.class) + .addClasses(MapperLocator.class, MapperLocatorDelegate.class, IgnoreIfMissing.class, JohnzonTextDecoder.class, JohnzonTextEncoder.class) .addPackages(true, JsonProviderImpl.class.getPackage()) .addPackages(true, Mapper.class.getPackage())) .addAsLibrary(jarLocation(Json.class)); diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md index 867cec7..f97517b 100644 --- a/src/site/markdown/index.md +++ b/src/site/markdown/index.md @@ -391,6 +391,13 @@ Integration is at codec level (encoder/decoder). There are two families of codec * The ones based on JSON-P (JsonObject, JsonArray, JsonStructure) * The ones based on Johnzon Mapper +Note that if you want to control the Mapper or JSON-B instance used by decoders you can set up the associated servlet listeners: + +* org.apache.johnzon.websocket.internal.mapper.MapperLocator for johnzon-mapper +* org.apache.johnzon.websocket.jsonb.JsonbLocator for JSON-B + +if you write in the servlet context an attribute named `org.apache.johnzon.websocket.internal.mapper.MapperLocator.mapper` (it is a `Supplier<Mapper>`) or `org.apache.johnzon.websocket.jsonb.JsonbLocator.jsonb` (depending the implementation you use) it will be used instead of the default instance. + #### JSON-P integration Encoders: @@ -415,6 +422,16 @@ Decoder: * `org.apache.johnzon.websocket.mapper.JohnzonTextDecoder` +#### JSON-B integration + +Encoder: + +* `org.apache.johnzon.websocket.jsonb.JsonbTextEncoder` + +Decoder: + +* `org.apache.johnzon.websocket.jsonb.JsonbTextDecoder` + #### Sample ##### JSON-P Samples