HtmlJsonProvider.java
/*
* Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package org.glassfish.jersey.media.htmljson;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import org.openide.util.lookup.ServiceProvider;
import org.openide.util.lookup.ServiceProviders;
import net.java.html.BrwsrCtx;
import net.java.html.json.Model;
import net.java.html.json.Models;
import net.java.html.json.Property;
/**
* Implementation of Jersey's message body reader and writer that
* can handle reading and writing of JSON models generated by {@link Model}
* annotation provided by
* <a target="_blank" href="http://bck2brwsr.apidesign.org/javadoc/net.java.html.json/">net.java.html.json</a>
* library. Include
* this JAR in your project and you can then use your
* model classes as Jersey's entities.
* <p>
* <pre>
* {@link Model @Model}(className="Query", properties={
* {@link Property @Property}(name="items", type=Item.<b>class</b>, array=true)
* })
* <b>class</b> QueryImpl {
*
* {@link Model @Model}(className="Item", properties={
* {@link Property @Property}(name="id", type=String.<b>class</b>),
* {@link Property @Property}(name="kind", type=Kind.<b>class</b>)
* })
* <b>class</b> ItemImpl {
* }
*
* <b>enum</b> Kind {
* GOOD, BAD
* }
*
* <b>public static</b> List{@code <Item>} doQuery() {
* {@link WebTarget} target = ...;
* Query q = target.request(MediaType.APPLICATION_JSON).get().readEntity(Query.<b>class</b>);
* return q.getItems();
* }
* }
* </pre>
*
* @author Jaroslav Tulach (jtulach at netbeans.org)
*/
@ServiceProviders({
@ServiceProvider(service = MessageBodyWriter.class),
@ServiceProvider(service = MessageBodyReader.class)
})
public final class HtmlJsonProvider implements MessageBodyWriter<Object>, MessageBodyReader<Object> {
@Override
public boolean isWriteable(Class clazz, Type type, Annotation[] antns, MediaType mt) {
if (!mt.isCompatible(MediaType.APPLICATION_JSON_TYPE)) {
return false;
}
if (clazz.isArray()) {
return Models.isModel(clazz.getComponentType());
}
if (java.util.List.class.isAssignableFrom(clazz)) {
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
Type[] args = pt.getActualTypeArguments();
if (args.length == 1 && args[0] instanceof Class) {
return Models.isModel((Class<?>) args[0]);
}
}
}
return Models.isModel(clazz);
}
@Override
public long getSize(Object t, Class type, Type type1, Annotation[] antns, MediaType mt) {
return -1;
}
@Override
public void writeTo(Object t, Class type, Type type1, Annotation[] antns, MediaType mt, MultivaluedMap mm, OutputStream out)
throws IOException, WebApplicationException {
dump(t, out);
}
private void dump(Object t, OutputStream out) throws IOException {
if (t instanceof Object[]) {
Object[] arr = (Object[]) t;
out.write('[');
for (int i = 0; i < arr.length; i++) {
if (i > 0) {
out.write(',');
}
dump(arr[i], out);
}
out.write(']');
} else {
out.write(t.toString().getBytes("UTF-8"));
}
}
@Override
public boolean isReadable(Class<?> type, Type type1, Annotation[] antns, MediaType mt) {
return isWriteable(type, type1, antns, mt);
}
@Override
public Object readFrom(Class<Object> clazz,
Type type, Annotation[] antns, MediaType mt,
MultivaluedMap<String, String> mm,
InputStream in) throws IOException, WebApplicationException {
BrwsrCtx def = BrwsrCtx.findDefault(HtmlJsonProvider.class);
if (clazz.isArray()) {
List<Object> res = new ArrayList<>();
final Class<?> cmp = clazz.getComponentType();
Models.parse(def, cmp, in, res);
Object[] arr = (Object[]) Array.newInstance(cmp, res.size());
return res.toArray(arr);
}
if (clazz.isAssignableFrom(java.util.List.class)
&& type instanceof ParameterizedType
&& ((ParameterizedType) type).getActualTypeArguments().length == 1
&& ((ParameterizedType) type).getActualTypeArguments()[0] instanceof Class) {
List<Object> res = new ArrayList<>();
final Class<?> cmp = (Class<?>) ((ParameterizedType) type).getActualTypeArguments()[0];
Models.parse(def, cmp, in, res);
return res;
}
return Models.parse(def, clazz, in);
}
}