Browse Source
Develop support class allowing JSR-356 Encoder and Decoder interfaces to delegate to Spring's ConversionService. Issue: SPR-10694pull/308/head
3 changed files with 622 additions and 0 deletions
@ -0,0 +1,247 @@
@@ -0,0 +1,247 @@
|
||||
/* |
||||
* Copyright 2002-2013 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.web.socket.adapter; |
||||
|
||||
import java.nio.ByteBuffer; |
||||
|
||||
import javax.websocket.DecodeException; |
||||
import javax.websocket.Decoder; |
||||
import javax.websocket.EncodeException; |
||||
import javax.websocket.Encoder; |
||||
import javax.websocket.EndpointConfig; |
||||
|
||||
import org.springframework.beans.BeansException; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.context.ConfigurableApplicationContext; |
||||
import org.springframework.core.GenericTypeResolver; |
||||
import org.springframework.core.convert.ConversionException; |
||||
import org.springframework.core.convert.ConversionService; |
||||
import org.springframework.core.convert.TypeDescriptor; |
||||
import org.springframework.util.Assert; |
||||
import org.springframework.web.context.ContextLoader; |
||||
|
||||
/** |
||||
* Base class that can be used to implement a standard {@link javax.websocket.Encoder} |
||||
* and/or {@link javax.websocket.Decoder}. It provides encode and decode method |
||||
* implementations that delegate to a Spring {@link ConversionService}. |
||||
* |
||||
* <p>By default, this class looks up a {@link ConversionService} registered in the |
||||
* {@link #getApplicationContext() active ApplicationContext} under |
||||
* the name {@code 'webSocketConversionService'}. This works fine for both client |
||||
* and server endpoints, in a Servlet container environment. If not running in a |
||||
* Servlet container, subclasses will need to override the |
||||
* {@link #getConversionService()} method to provide an alternative lookup strategy. |
||||
* |
||||
* <p>Subclasses can extend this class and should also implement one or |
||||
* both of {@link javax.websocket.Encoder} and {@link javax.websocket.Decoder}. |
||||
* For convenience {@link ConvertingEncoderDecoderSupport.BinaryEncoder}, |
||||
* {@link ConvertingEncoderDecoderSupport.BinaryDecoder}, |
||||
* {@link ConvertingEncoderDecoderSupport.TextEncoder} and |
||||
* {@link ConvertingEncoderDecoderSupport.TextDecoder} subclasses are provided. |
||||
* |
||||
* <p>Since JSR-356 only allows Encoder/Decoder to be registered by type, instances |
||||
* of this class are therefore managed by the WebSocket runtime, and do not need to |
||||
* be registered as Spring Beans. They can, however, by injected with Spring-managed |
||||
* dependencies via {@link Autowired @Autowire}. |
||||
* |
||||
* <p>Converters to convert between the {@link #getType() type} and {@code String} or |
||||
* {@code ByteBuffer} should be registered. |
||||
* |
||||
* @author Phillip Webb |
||||
* @since 4.0 |
||||
* |
||||
* @param <T> The type being converted to (for Encoder) or from (for Decoder) |
||||
* @param <M> The WebSocket message type ({@link String} or {@link ByteBuffer}) |
||||
* |
||||
* @see ConvertingEncoderDecoderSupport.BinaryEncoder |
||||
* @see ConvertingEncoderDecoderSupport.BinaryDecoder |
||||
* @see ConvertingEncoderDecoderSupport.TextEncoder |
||||
* @see ConvertingEncoderDecoderSupport.TextDecoder |
||||
*/ |
||||
public abstract class ConvertingEncoderDecoderSupport<T, M> { |
||||
|
||||
private static final String CONVERSION_SERVICE_BEAN_NAME = "webSocketConversionService"; |
||||
|
||||
|
||||
/** |
||||
* @see javax.websocket.Encoder#init(EndpointConfig) |
||||
* @see javax.websocket.Decoder#init(EndpointConfig) |
||||
*/ |
||||
public void init(EndpointConfig config) { |
||||
ApplicationContext applicationContext = getApplicationContext(); |
||||
if (applicationContext != null && applicationContext instanceof ConfigurableApplicationContext) { |
||||
ConfigurableListableBeanFactory beanFactory = |
||||
((ConfigurableApplicationContext) applicationContext).getBeanFactory(); |
||||
beanFactory.autowireBean(this); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @see javax.websocket.Encoder#destroy() |
||||
* @see javax.websocket.Decoder#destroy() |
||||
*/ |
||||
public void destroy() { |
||||
} |
||||
|
||||
/** |
||||
* Strategy method used to obtain the {@link ConversionService}. By default this |
||||
* method expects a bean named {@code 'webSocketConversionService'} in the |
||||
* {@link #getApplicationContext() active ApplicationContext}. |
||||
* @return the {@link ConversionService} (never null) |
||||
*/ |
||||
protected ConversionService getConversionService() { |
||||
ApplicationContext applicationContext = getApplicationContext(); |
||||
Assert.state(applicationContext != null, |
||||
"Unable to locate the Spring ApplicationContext"); |
||||
try { |
||||
return applicationContext.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class); |
||||
} |
||||
catch (BeansException ex) { |
||||
throw new IllegalStateException( |
||||
"Unable to find ConversionService, please configure a '" |
||||
+ CONVERSION_SERVICE_BEAN_NAME + "' or override getConversionService()", ex); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns the active {@link ApplicationContext}. Be default this method obtains |
||||
* the context via {@link ContextLoader#getCurrentWebApplicationContext()}, which |
||||
* finds the ApplicationContext loaded via {@link ContextLoader} typically in a |
||||
* Servlet container environment. When not running in a Servlet container and |
||||
* not using {@link ContextLoader}, this method should be overridden. |
||||
* @return the {@link ApplicationContext} or {@code null} |
||||
*/ |
||||
protected ApplicationContext getApplicationContext() { |
||||
return ContextLoader.getCurrentWebApplicationContext(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the type being converted. By default the type is resolved using |
||||
* the generic arguments of the class. |
||||
*/ |
||||
protected TypeDescriptor getType() { |
||||
return TypeDescriptor.valueOf(resolveTypeArguments()[0]); |
||||
} |
||||
|
||||
/** |
||||
* Returns the websocket message type. By default the type is resolved using |
||||
* the generic arguments of the class. |
||||
*/ |
||||
protected TypeDescriptor getMessageType() { |
||||
return TypeDescriptor.valueOf(resolveTypeArguments()[1]); |
||||
} |
||||
|
||||
private Class<?>[] resolveTypeArguments() { |
||||
return GenericTypeResolver.resolveTypeArguments(getClass(), |
||||
ConvertingEncoderDecoderSupport.class); |
||||
} |
||||
|
||||
/** |
||||
* @see javax.websocket.Encoder.Text#encode(Object) |
||||
* @see javax.websocket.Encoder.Binary#encode(Object) |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public M encode(T object) throws EncodeException { |
||||
try { |
||||
return (M) getConversionService().convert(object, getType(), getMessageType()); |
||||
} |
||||
catch (ConversionException ex) { |
||||
throw new EncodeException(object, "Unable to encode websocket message using ConversionService", ex); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @see javax.websocket.Decoder.Text#willDecode(String) |
||||
* @see javax.websocket.Decoder.Binary#willDecode(ByteBuffer) |
||||
*/ |
||||
public boolean willDecode(M bytes) { |
||||
return getConversionService().canConvert(getType(), getMessageType()); |
||||
} |
||||
|
||||
/** |
||||
* @see javax.websocket.Decoder.Text#decode(String) |
||||
* @see javax.websocket.Decoder.Binary#decode(ByteBuffer) |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public T decode(M message) throws DecodeException { |
||||
try { |
||||
return (T) getConversionService().convert(message, getMessageType(), getType()); |
||||
} |
||||
catch (ConversionException ex) { |
||||
if (message instanceof String) { |
||||
throw new DecodeException((String) message, "Unable to decode " + |
||||
"websocket message using ConversionService", ex); |
||||
} |
||||
if (message instanceof ByteBuffer) { |
||||
throw new DecodeException((ByteBuffer) message, "Unable to decode " + |
||||
"websocket message using ConversionService", ex); |
||||
} |
||||
throw ex; |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* A Binary {@link javax.websocket.Encoder.Binary javax.websocket.Encoder} that |
||||
* delegates to Spring's conversion service. See |
||||
* {@link ConvertingEncoderDecoderSupport} for details. |
||||
* |
||||
* @param <T> The type that this Encoder can convert to. |
||||
*/ |
||||
public static abstract class BinaryEncoder<T> extends |
||||
ConvertingEncoderDecoderSupport<T, ByteBuffer> implements Encoder.Binary<T> { |
||||
} |
||||
|
||||
|
||||
/** |
||||
* A Binary {@link javax.websocket.Encoder.Binary javax.websocket.Encoder} that delegates |
||||
* to Spring's conversion service. See {@link ConvertingEncoderDecoderSupport} for |
||||
* details. |
||||
* |
||||
* @param <T> The type that this Decoder can convert from. |
||||
*/ |
||||
public static abstract class BinaryDecoder<T> extends |
||||
ConvertingEncoderDecoderSupport<T, ByteBuffer> implements Decoder.Binary<T> { |
||||
} |
||||
|
||||
|
||||
/** |
||||
* A Text {@link javax.websocket.Encoder.Text javax.websocket.Encoder} that delegates |
||||
* to Spring's conversion service. See {@link ConvertingEncoderDecoderSupport} for |
||||
* details. |
||||
* |
||||
* @param <T> The type that this Encoder can convert to. |
||||
*/ |
||||
public static abstract class TextEncoder<T> extends |
||||
ConvertingEncoderDecoderSupport<T, String> implements Encoder.Text<T> { |
||||
} |
||||
|
||||
|
||||
/** |
||||
* A Text {@link javax.websocket.Encoder.Text javax.websocket.Encoder} that delegates |
||||
* to Spring's conversion service. See {@link ConvertingEncoderDecoderSupport} for |
||||
* details. |
||||
* |
||||
* @param <T> The type that this Decoder can convert from. |
||||
*/ |
||||
public static abstract class TextDecoder<T> extends |
||||
ConvertingEncoderDecoderSupport<T, String> implements Decoder.Text<T> { |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,58 @@
@@ -0,0 +1,58 @@
|
||||
/* |
||||
* Copyright 2002-2013 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.web.socket; |
||||
|
||||
import java.lang.reflect.Field; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.web.context.ContextLoader; |
||||
import org.springframework.web.context.WebApplicationContext; |
||||
|
||||
/** |
||||
* General test utilities for manipulating the {@link ContextLoader}. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
public class ContextLoaderTestUtils { |
||||
|
||||
private static Map<ClassLoader, WebApplicationContext> currentContextPerThread = getCurrentContextPerThreadFromContextLoader(); |
||||
|
||||
public static void setCurrentWebApplicationContext(WebApplicationContext applicationContext) { |
||||
setCurrentWebApplicationContext(Thread.currentThread().getContextClassLoader(), applicationContext); |
||||
} |
||||
|
||||
public static void setCurrentWebApplicationContext(ClassLoader classLoader, WebApplicationContext applicationContext) { |
||||
if(applicationContext != null) { |
||||
currentContextPerThread.put(classLoader, applicationContext); |
||||
} else { |
||||
currentContextPerThread.remove(classLoader); |
||||
} |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private static Map<ClassLoader, WebApplicationContext> getCurrentContextPerThreadFromContextLoader() { |
||||
try { |
||||
Field field = ContextLoader.class.getDeclaredField("currentContextPerThread"); |
||||
field.setAccessible(true); |
||||
return (Map<ClassLoader, WebApplicationContext>) field.get(null); |
||||
} |
||||
catch (Exception ex) { |
||||
throw new IllegalStateException(ex); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,317 @@
@@ -0,0 +1,317 @@
|
||||
/* |
||||
* Copyright 2002-2013 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.web.socket.adapter; |
||||
|
||||
import java.nio.ByteBuffer; |
||||
|
||||
import javax.websocket.DecodeException; |
||||
import javax.websocket.Decoder; |
||||
import javax.websocket.EncodeException; |
||||
import javax.websocket.Encoder; |
||||
|
||||
import org.junit.After; |
||||
import org.junit.Before; |
||||
import org.junit.Rule; |
||||
import org.junit.Test; |
||||
import org.junit.rules.ExpectedException; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.core.convert.ConversionService; |
||||
import org.springframework.core.convert.ConverterNotFoundException; |
||||
import org.springframework.core.convert.converter.Converter; |
||||
import org.springframework.core.convert.support.ByteBufferConverter; |
||||
import org.springframework.core.convert.support.GenericConversionService; |
||||
import org.springframework.web.context.WebApplicationContext; |
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; |
||||
import org.springframework.web.socket.ContextLoaderTestUtils; |
||||
|
||||
import static org.hamcrest.Matchers.*; |
||||
import static org.junit.Assert.*; |
||||
|
||||
/** |
||||
* Test for {@link ConvertingEncoderDecoderSupport}. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
public class ConvertingEncoderDecoderSupportTests { |
||||
|
||||
private static final String CONVERTED_TEXT = "_test"; |
||||
|
||||
private static final ByteBuffer CONVERTED_BYTES = ByteBuffer.wrap("~test".getBytes()); |
||||
|
||||
|
||||
@Rule |
||||
public ExpectedException thown = ExpectedException.none(); |
||||
|
||||
private WebApplicationContext applicationContext; |
||||
|
||||
private MyType myType = new MyType("test"); |
||||
|
||||
|
||||
@Before |
||||
public void setup() { |
||||
setup(Config.class); |
||||
} |
||||
|
||||
@After |
||||
public void teardown() { |
||||
ContextLoaderTestUtils.setCurrentWebApplicationContext(null); |
||||
} |
||||
|
||||
private void setup(Class<?> configurationClass) { |
||||
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext(); |
||||
applicationContext.register(configurationClass); |
||||
applicationContext.refresh(); |
||||
this.applicationContext = applicationContext; |
||||
ContextLoaderTestUtils.setCurrentWebApplicationContext(this.applicationContext); |
||||
} |
||||
|
||||
@Test |
||||
public void encodeToText() throws Exception { |
||||
assertThat(new MyTextEncoder().encode(myType), equalTo(CONVERTED_TEXT)); |
||||
} |
||||
|
||||
@Test |
||||
public void encodeToTextCannotConvert() throws Exception { |
||||
setup(NoConvertersConfig.class); |
||||
thown.expect(EncodeException.class); |
||||
thown.expectCause(isA(ConverterNotFoundException.class)); |
||||
new MyTextEncoder().encode(myType); |
||||
} |
||||
|
||||
@Test |
||||
public void encodeToBinary() throws Exception { |
||||
assertThat(new MyBinaryEncoder().encode(myType).array(), |
||||
equalTo(CONVERTED_BYTES.array())); |
||||
} |
||||
|
||||
@Test |
||||
public void encodeToBinaryCannotConvert() throws Exception { |
||||
setup(NoConvertersConfig.class); |
||||
thown.expect(EncodeException.class); |
||||
thown.expectCause(isA(ConverterNotFoundException.class)); |
||||
new MyBinaryEncoder().encode(myType); |
||||
} |
||||
|
||||
@Test |
||||
public void decodeFromText() throws Exception { |
||||
Decoder.Text<MyType> decoder = new MyTextDecoder(); |
||||
assertThat(decoder.willDecode(CONVERTED_TEXT), is(true)); |
||||
assertThat(decoder.decode(CONVERTED_TEXT), equalTo(myType)); |
||||
} |
||||
|
||||
@Test |
||||
public void decodeFromTextCannotConvert() throws Exception { |
||||
setup(NoConvertersConfig.class); |
||||
Decoder.Text<MyType> decoder = new MyTextDecoder(); |
||||
assertThat(decoder.willDecode(CONVERTED_TEXT), is(false)); |
||||
thown.expect(DecodeException.class); |
||||
thown.expectCause(isA(ConverterNotFoundException.class)); |
||||
decoder.decode(CONVERTED_TEXT); |
||||
} |
||||
|
||||
@Test |
||||
public void decodeFromBinary() throws Exception { |
||||
Decoder.Binary<MyType> decoder = new MyBinaryDecoder(); |
||||
assertThat(decoder.willDecode(CONVERTED_BYTES), is(true)); |
||||
assertThat(decoder.decode(CONVERTED_BYTES), equalTo(myType)); |
||||
} |
||||
|
||||
@Test |
||||
public void decodeFromBinaryCannotConvert() throws Exception { |
||||
setup(NoConvertersConfig.class); |
||||
Decoder.Binary<MyType> decoder = new MyBinaryDecoder(); |
||||
assertThat(decoder.willDecode(CONVERTED_BYTES), is(false)); |
||||
thown.expect(DecodeException.class); |
||||
thown.expectCause(isA(ConverterNotFoundException.class)); |
||||
decoder.decode(CONVERTED_BYTES); |
||||
} |
||||
|
||||
@Test |
||||
public void encodeAndDecodeText() throws Exception { |
||||
MyTextEncoderDecoder encoderDecoder = new MyTextEncoderDecoder(); |
||||
String encoded = encoderDecoder.encode(myType); |
||||
assertThat(encoderDecoder.decode(encoded), equalTo(myType)); |
||||
} |
||||
|
||||
@Test |
||||
public void encodeAndDecodeBytes() throws Exception { |
||||
MyBinaryEncoderDecoder encoderDecoder = new MyBinaryEncoderDecoder(); |
||||
ByteBuffer encoded = encoderDecoder.encode(myType); |
||||
assertThat(encoderDecoder.decode(encoded), equalTo(myType)); |
||||
} |
||||
|
||||
@Test |
||||
public void autowiresIntoEncoder() throws Exception { |
||||
WithAutowire withAutowire = new WithAutowire(); |
||||
withAutowire.init(null); |
||||
assertThat(withAutowire.config, equalTo(applicationContext.getBean(Config.class))); |
||||
} |
||||
|
||||
@Test |
||||
public void cannotFindApplicationContext() throws Exception { |
||||
ContextLoaderTestUtils.setCurrentWebApplicationContext(null); |
||||
WithAutowire encoder = new WithAutowire(); |
||||
encoder.init(null); |
||||
thown.expect(IllegalStateException.class); |
||||
thown.expectMessage("Unable to locate the Spring ApplicationContext"); |
||||
encoder.encode(myType); |
||||
} |
||||
|
||||
@Test |
||||
public void cannotFindConversionService() throws Exception { |
||||
setup(NoConfig.class); |
||||
MyBinaryEncoder encoder = new MyBinaryEncoder(); |
||||
encoder.init(null); |
||||
thown.expect(IllegalStateException.class); |
||||
thown.expectMessage("Unable to find ConversionService"); |
||||
encoder.encode(myType); |
||||
} |
||||
|
||||
@Configuration |
||||
public static class Config { |
||||
|
||||
@Bean |
||||
public ConversionService webSocketConversionService() { |
||||
GenericConversionService conversionService = new GenericConversionService(); |
||||
conversionService.addConverter(new ByteBufferConverter(conversionService)); |
||||
conversionService.addConverter(new MyTypeToStringConverter()); |
||||
conversionService.addConverter(new MyTypeToBytesConverter()); |
||||
conversionService.addConverter(new StringToMyTypeConverter()); |
||||
conversionService.addConverter(new BytesToMyTypeConverter()); |
||||
return conversionService; |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
public static class NoConvertersConfig { |
||||
|
||||
@Bean |
||||
public ConversionService webSocketConversionService() { |
||||
return new GenericConversionService(); |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
@Configuration |
||||
public static class NoConfig { |
||||
} |
||||
|
||||
|
||||
public static class MyType { |
||||
|
||||
private String value; |
||||
|
||||
public MyType(String value) { |
||||
this.value = value; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return this.value; |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return value.hashCode(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object obj) { |
||||
if(obj instanceof MyType) { |
||||
return ((MyType)obj).value.equals(value); |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
|
||||
private static class MyTypeToStringConverter implements Converter<MyType, String> { |
||||
@Override |
||||
public String convert(MyType source) { |
||||
return "_" + source.toString(); |
||||
} |
||||
} |
||||
|
||||
|
||||
private static class MyTypeToBytesConverter implements Converter<MyType, byte[]> { |
||||
@Override |
||||
public byte[] convert(MyType source) { |
||||
return ("~" + source.toString()).getBytes(); |
||||
} |
||||
} |
||||
|
||||
|
||||
private static class StringToMyTypeConverter implements Converter<String, MyType> { |
||||
@Override |
||||
public MyType convert(String source) { |
||||
return new MyType(source.substring(1)); |
||||
} |
||||
} |
||||
|
||||
|
||||
private static class BytesToMyTypeConverter implements Converter<byte[], MyType> { |
||||
@Override |
||||
public MyType convert(byte[] source) { |
||||
return new MyType(new String(source).substring(1)); |
||||
} |
||||
} |
||||
|
||||
|
||||
public static class MyTextEncoder extends |
||||
ConvertingEncoderDecoderSupport.TextEncoder<MyType> { |
||||
} |
||||
|
||||
|
||||
public static class MyBinaryEncoder extends |
||||
ConvertingEncoderDecoderSupport.BinaryEncoder<MyType> { |
||||
} |
||||
|
||||
|
||||
public static class MyTextDecoder extends |
||||
ConvertingEncoderDecoderSupport.TextDecoder<MyType> { |
||||
} |
||||
|
||||
|
||||
public static class MyBinaryDecoder extends |
||||
ConvertingEncoderDecoderSupport.BinaryDecoder<MyType> { |
||||
} |
||||
|
||||
|
||||
public static class MyTextEncoderDecoder extends |
||||
ConvertingEncoderDecoderSupport<MyType, String> implements Encoder.Text<MyType>, |
||||
Decoder.Text<MyType> { |
||||
} |
||||
|
||||
|
||||
public static class MyBinaryEncoderDecoder extends |
||||
ConvertingEncoderDecoderSupport<MyType, ByteBuffer> implements Encoder.Binary<MyType>, |
||||
Decoder.Binary<MyType> { |
||||
} |
||||
|
||||
|
||||
public static class WithAutowire extends ConvertingEncoderDecoderSupport.TextDecoder<MyType> { |
||||
|
||||
@Autowired |
||||
private Config config; |
||||
|
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue