Remove dependency on web classes from new Encoder/Decoder implementation

The web dependency still need to be there since it appears that spring-rsocket requires it
This commit is contained in:
Oleg Zhurakousky
2021-03-05 15:08:25 +01:00
parent 498a52ee84
commit 9f8c29a4e7
2 changed files with 80 additions and 13 deletions

View File

@@ -16,27 +16,35 @@
package org.springframework.cloud.function.rsocket;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.util.Map;
import org.reactivestreams.Publisher;
import org.springframework.cloud.function.context.catalog.FunctionTypeUtils;
import org.springframework.cloud.function.json.JsonMapper;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.AbstractDecoder;
import org.springframework.core.codec.DecodingException;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.lang.Nullable;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import reactor.core.publisher.Flux;
/**
*
* @author Oleg Zhurakousky
* @since 3.1
*
*/
class MessageAwareJsonDecoder extends Jackson2JsonDecoder {
class MessageAwareJsonDecoder extends AbstractDecoder<Object> {
private final JsonMapper jsonMapper;
@@ -49,22 +57,25 @@ class MessageAwareJsonDecoder extends Jackson2JsonDecoder {
return mimeType.isCompatibleWith(MimeTypeUtils.APPLICATION_JSON);
}
@SuppressWarnings("unchecked")
@Override
public Object decode(DataBuffer dataBuffer, ResolvableType targetType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) throws DecodingException {
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints)
throws DecodingException {
ResolvableType type = ResolvableType.forClassWithGenerics(Map.class, String.class, Object.class);
Map<String, Object> messageMap = (Map<String, Object>) super.decode(dataBuffer, type, mimeType, hints);
ResolvableType type = ResolvableType.forClassWithGenerics(Map.class, String.class,
Object.class);
Map<String, Object> messageMap = (Map<String, Object>) doDecode(dataBuffer, type,
mimeType, hints);
if (messageMap.containsKey(FunctionRSocketUtils.PAYLOAD)) {
Type requestedType = FunctionTypeUtils.getGenericType(targetType.getType());
Object payload = this.jsonMapper.fromJson(messageMap.get(FunctionRSocketUtils.PAYLOAD), requestedType);
Object payload = this.jsonMapper.fromJson(
messageMap.get(FunctionRSocketUtils.PAYLOAD), requestedType);
if (FunctionTypeUtils.isMessage(targetType.getType())) {
return MessageBuilder.withPayload(payload)
.copyHeaders((Map<String, ?>) messageMap.get(FunctionRSocketUtils.HEADERS))
.build();
return MessageBuilder.withPayload(payload).copyHeaders(
(Map<String, ?>) messageMap.get(FunctionRSocketUtils.HEADERS))
.build();
}
else {
return payload;
@@ -73,6 +84,45 @@ class MessageAwareJsonDecoder extends Jackson2JsonDecoder {
else {
return messageMap;
}
}
private Object doDecode(DataBuffer dataBuffer, ResolvableType targetType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints)
throws DecodingException {
try {
byte[] data = toByteArray(dataBuffer.asInputStream());
return this.jsonMapper.fromJson(data, targetType.getType());
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
finally {
DataBufferUtils.release(dataBuffer);
}
}
private byte[] toByteArray(final InputStream input) throws IOException {
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
copyLarge(input, output, new byte[2048]);
return output.toByteArray();
}
}
private long copyLarge(final InputStream input, final OutputStream output,
final byte[] buffer) throws IOException {
long count = 0;
int n;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
@Override
public Flux<Object> decode(Publisher<DataBuffer> inputStream,
ResolvableType elementType, MimeType mimeType, Map<String, Object> hints) {
return Flux.from(inputStream).map(buffer -> decode(buffer, elementType, mimeType, hints));
}
}

View File

@@ -20,29 +20,36 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.reactivestreams.Publisher;
import org.springframework.cloud.function.context.catalog.FunctionTypeUtils;
import org.springframework.cloud.function.json.JsonMapper;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.AbstractEncoder;
import org.springframework.core.codec.ByteArrayEncoder;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import reactor.core.publisher.Flux;
/**
*
* An extended implementation
* @author Oleg Zhurakousky
* @since 3.1
*
*/
class MessageAwareJsonEncoder extends Jackson2JsonEncoder {
class MessageAwareJsonEncoder extends AbstractEncoder<Object> {
private final JsonMapper mapper;
private final boolean isClient;
private final ByteArrayEncoder byteArrayEncoder;
MessageAwareJsonEncoder(JsonMapper mapper) {
this(mapper, false);
}
@@ -50,6 +57,7 @@ class MessageAwareJsonEncoder extends Jackson2JsonEncoder {
MessageAwareJsonEncoder(JsonMapper mapper, boolean isClient) {
this.mapper = mapper;
this.isClient = isClient;
this.byteArrayEncoder = new ByteArrayEncoder();
}
@Override
@@ -81,6 +89,15 @@ class MessageAwareJsonEncoder extends Jackson2JsonEncoder {
}
value = Collections.singletonMap(FunctionRSocketUtils.PAYLOAD, value);
}
return super.encodeValue(value, bufferFactory, valueType, mimeType, hints);
byte[] data = this.mapper.toJson(value);
return this.byteArrayEncoder.encodeValue(data, bufferFactory, valueType, mimeType, hints);
}
@Override
public Flux<DataBuffer> encode(Publisher<? extends Object> inputStream,
DataBufferFactory bufferFactory, ResolvableType elementType,
MimeType mimeType, Map<String, Object> hints) {
return Flux.from(inputStream).map(value ->
encodeValue(value, bufferFactory, elementType, mimeType, hints));
}
}