Skip to content

Commit ec321b6

Browse files
committed
Add protobuf message provider
1 parent b3fbf0b commit ec321b6

File tree

4 files changed

+175
-0
lines changed

4 files changed

+175
-0
lines changed

runtime/jaxrs/src/main/java/com/flit/runtime/jaxrs/FlitExceptionMapper.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
import javax.ws.rs.core.MediaType;
99
import javax.ws.rs.core.Response;
1010
import javax.ws.rs.ext.ExceptionMapper;
11+
import javax.ws.rs.ext.Provider;
1112
import org.slf4j.Logger;
1213
import org.slf4j.LoggerFactory;
1314

15+
@Provider
1416
public class FlitExceptionMapper implements ExceptionMapper<FlitException> {
1517

1618
private static final Logger LOGGER = LoggerFactory.getLogger(FlitExceptionMapper.class);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.flit.runtime.jaxrs;
2+
3+
import com.flit.runtime.ErrorCode;
4+
import com.google.protobuf.InvalidProtocolBufferException;
5+
import java.util.HashMap;
6+
import java.util.Map;
7+
import javax.servlet.http.HttpServletRequest;
8+
import javax.ws.rs.core.Context;
9+
import javax.ws.rs.core.MediaType;
10+
import javax.ws.rs.core.Response;
11+
import javax.ws.rs.ext.ExceptionMapper;
12+
import org.slf4j.Logger;
13+
import org.slf4j.LoggerFactory;
14+
15+
public class InvalidProtobufExceptionMapper implements
16+
ExceptionMapper<InvalidProtocolBufferException> {
17+
18+
private static final Logger LOGGER = LoggerFactory
19+
.getLogger(InvalidProtobufExceptionMapper.class);
20+
21+
@Context private HttpServletRequest request;
22+
23+
@Override
24+
public Response toResponse(InvalidProtocolBufferException exception) {
25+
LOGGER.error("InvalidProtocolBufferException: request = {}, method = {}, msg= {}",
26+
request.getRequestURI(), request.getMethod(), exception.getMessage(), exception);
27+
28+
Map<String, Object> response = new HashMap<>();
29+
response.put("code", ErrorCode.INVALID_ARGUMENT.getErrorCode());
30+
response.put("msg", exception.getMessage());
31+
return Response.status(ErrorCode.INVALID_ARGUMENT.getHttpStatus())
32+
.type(MediaType.APPLICATION_JSON)
33+
.entity(response)
34+
.build();
35+
}
36+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package com.flit.runtime.jaxrs;
2+
3+
import com.google.protobuf.Message;
4+
import com.google.protobuf.util.JsonFormat;
5+
import java.io.ByteArrayOutputStream;
6+
import java.io.IOException;
7+
import java.io.InputStream;
8+
import java.io.InputStreamReader;
9+
import java.io.OutputStream;
10+
import java.lang.annotation.Annotation;
11+
import java.lang.reflect.Method;
12+
import java.lang.reflect.Type;
13+
import java.nio.charset.StandardCharsets;
14+
import javax.ws.rs.WebApplicationException;
15+
import javax.ws.rs.core.MediaType;
16+
import javax.ws.rs.core.MultivaluedMap;
17+
import javax.ws.rs.ext.MessageBodyReader;
18+
import javax.ws.rs.ext.MessageBodyWriter;
19+
import javax.ws.rs.ext.Provider;
20+
21+
@Provider
22+
public class ProtobufMessageProvider implements MessageBodyWriter<Message>,
23+
MessageBodyReader<Message> {
24+
25+
@Override
26+
public boolean isWriteable(Class<?> type, Type genericType,
27+
Annotation[] annotations, MediaType mediaType) {
28+
return Message.class.isAssignableFrom(type) && (
29+
"json".equals(mediaType.getSubtype()) || "protobuf".equals(mediaType.getSubtype()));
30+
}
31+
32+
@Override
33+
public long getSize(Message t, Class<?> type,
34+
Type genericType, Annotation[] annotations,
35+
MediaType mediaType) {
36+
if (t == null) {
37+
return -1;
38+
}
39+
ByteArrayOutputStream out = new java.io.ByteArrayOutputStream();
40+
try {
41+
writeTo(t, type, genericType, annotations, mediaType, null, out);
42+
} catch (java.io.IOException e) {
43+
return -1;
44+
}
45+
return out.size();
46+
}
47+
48+
@Override
49+
public void writeTo(Message t, Class<?> type,
50+
Type genericType, Annotation[] annotations,
51+
MediaType mediaType,
52+
MultivaluedMap<String, Object> httpHeaders,
53+
OutputStream entityStream)
54+
throws IOException, WebApplicationException {
55+
switch (mediaType.getSubtype()) {
56+
case "protobuf":
57+
t.writeTo(entityStream);
58+
break;
59+
case "json":
60+
entityStream
61+
.write(JsonFormat.printer().print(t).getBytes(StandardCharsets.UTF_8));
62+
break;
63+
default:
64+
throw new WebApplicationException("MediaType not supported!");
65+
}
66+
}
67+
68+
@Override
69+
public boolean isReadable(Class<?> type, Type genericType,
70+
Annotation[] annotations, MediaType mediaType) {
71+
return Message.class.isAssignableFrom(type) && (
72+
"json".equals(mediaType.getSubtype()) || "protobuf".equals(mediaType.getSubtype()));
73+
}
74+
75+
@Override
76+
public Message readFrom(Class<Message> type, Type genericType, Annotation[] annotations,
77+
MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
78+
throws WebApplicationException {
79+
try {
80+
switch (mediaType.getSubtype()) {
81+
case "protobuf":
82+
Method m = type.getMethod("parseFrom", InputStream.class);
83+
return (Message) m.invoke(null, entityStream);
84+
case "json":
85+
Message.Builder msg = (Message.Builder) type
86+
.getMethod("newBuilder").invoke(null);
87+
JsonFormat.parser()
88+
.merge(new InputStreamReader(entityStream), msg);
89+
return msg.build();
90+
default:
91+
throw new WebApplicationException("MediaType not supported!");
92+
}
93+
} catch (Exception e) {
94+
throw new WebApplicationException(e);
95+
}
96+
}
97+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.flit.runtime.jaxrs;
2+
3+
import static org.junit.Assert.assertEquals;
4+
5+
import com.google.protobuf.InvalidProtocolBufferException;
6+
import java.util.Map;
7+
import javax.servlet.http.HttpServletRequest;
8+
import javax.ws.rs.core.MediaType;
9+
import javax.ws.rs.core.Response;
10+
import org.junit.Before;
11+
import org.junit.Test;
12+
import org.mockito.InjectMocks;
13+
import org.mockito.Mock;
14+
import org.mockito.MockitoAnnotations;
15+
16+
public class InvalidProtobufExceptionMapperTest {
17+
18+
@Mock
19+
private HttpServletRequest request;
20+
21+
@InjectMocks
22+
private InvalidProtobufExceptionMapper mapper = new InvalidProtobufExceptionMapper();
23+
24+
@Before
25+
public void setup() {
26+
MockitoAnnotations.initMocks(this);
27+
}
28+
29+
@Test
30+
public void testToResponse() {
31+
InvalidProtocolBufferException exception = new InvalidProtocolBufferException(
32+
"something happened");
33+
Response response = mapper.toResponse(exception);
34+
assertEquals(response.getStatus(), 400);
35+
Map<String, Object> expectedResult = Map
36+
.of("msg", "something happened", "code", "invalid_argument");
37+
assertEquals(response.getEntity(), expectedResult);
38+
assertEquals(response.getMediaType(), MediaType.APPLICATION_JSON_TYPE);
39+
}
40+
}

0 commit comments

Comments
 (0)