Skip to content

Instantly share code, notes, and snippets.

@romain-grecourt
Last active September 15, 2018 04:43
Show Gist options
  • Save romain-grecourt/d2b04178140f7eab3b69f8ea2481fc10 to your computer and use it in GitHub Desktop.
Save romain-grecourt/d2b04178140f7eab3b69f8ea2481fc10 to your computer and use it in GitHub Desktop.
helidon jsonb support
public class JsonbSupport implements Service, Handler {
private final Jsonb jsonb;
private final Class type;
private final Type runtimeType;
private JsonbSupport(Class type, Type runtimeType, JsonbConfig config){
Objects.requireNonNull(type, "type is null");
this.type = type;
this.runtimeType = runtimeType;
if(config != null){
jsonb = JsonbBuilder.create(config);
} else {
jsonb = JsonbBuilder.create();
}
}
@Override
public void update(Routing.Rules routingRules) {
routingRules.any(this);
}
@Override
public void accept(ServerRequest req, ServerResponse res) {
// Reader
req.content()
.registerReader(type::isAssignableFrom, (publisher, clazz) -> {
return reader().apply(publisher);
});
// Writer
res.registerWriter(obj -> (type.isAssignableFrom(obj.getClass()))
&& testOrSetContentType(req, res),
bean -> {
return writer().apply(bean);
});
req.next();
}
private boolean testOrSetContentType(ServerRequest request, ServerResponse response) {
MediaType mt = response.headers().contentType().orElse(null);
if (mt == null) {
// Find if accepts any JSON compatible type
List<MediaType> acceptedTypes = request.headers().acceptedTypes();
MediaType preferredType;
if (acceptedTypes.isEmpty()) {
preferredType = MediaType.APPLICATION_JSON;
} else {
preferredType = acceptedTypes
.stream()
.map(clazz -> {
if (clazz.test(MediaType.APPLICATION_JSON)) {
return MediaType.APPLICATION_JSON;
} else if (clazz.hasSuffix("json")) {
return new MediaType(clazz.getType(), clazz.getSubtype());
} else {
return null;
}
})
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
if (preferredType == null) {
return false;
} else {
response.headers().contentType(preferredType);
return true;
}
} else {
return MediaType.JSON_PREDICATE.test(mt);
}
}
public Reader<Object> reader() {
return (publisher, clazz) -> {
// TODO issue when using inputstream reader.
// seems to point at a bug in the publisher inputstream impl in webserver
return ContentReaders.stringReader(Charset.defaultCharset())
.apply(publisher)
.thenApply(str -> {
if (runtimeType != null) {
return jsonb.fromJson(str, runtimeType);
}
return jsonb.fromJson(str, type);
});
};
}
public Function<Object, Publisher<ResponseChunk>> writer() {
return obj -> {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
jsonb.toJson(obj, baos);
return ContentWriters.byteArrayWriter(false)
.apply(baos.toByteArray());
};
}
public static class Builder {
private Class type;
private Type runtimeType;
private JsonbConfig config;
public Builder type(Class type){
this.type = type;
return this;
}
public Builder runtimeType(Type type){
this.runtimeType = type;
return this;
}
public Builder config(JsonbConfig config){
this.config = config;
return this;
}
public JsonbSupport build(){
return new JsonbSupport(type, runtimeType, config);
}
}
public static Builder builder(){
return new Builder();
}
}
private static Routing createRouting() {
return Routing.builder()
.register(JsonbSupport.builder()
.type(Dog.class)
.config(new JsonbConfig()
.withNullValues(true))
.build())
.post("/test", Main::test)
.build();
}
private static void test(ServerRequest req, ServerResponse res){
req.content()
.as(Dog.class)
.thenAccept(res::send);
}
<dependency>
<groupId>javax.json.bind</groupId>
<artifactId>javax.json.bind-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>javax.json</groupId>
<artifactId>javax.json-api</artifactId>
<version>1.1.2</version>
</dependency>
curl -vvv -H "Content-Type: application/json" -d '{"age":4,"bitable":false,"name":"Falco"}' http://localhost:8080/test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment