001/* 002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Nicolas Chapurlat <nchapurlat@nuxeo.com> 016 */ 017 018package org.nuxeo.ecm.core.io.marshallers.json; 019 020import static javax.ws.rs.core.MediaType.APPLICATION_JSON; 021import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; 022 023import java.io.IOException; 024import java.io.OutputStream; 025import java.lang.reflect.Type; 026 027import javax.inject.Inject; 028import javax.ws.rs.core.MediaType; 029 030import org.codehaus.jackson.JsonGenerator; 031import org.nuxeo.ecm.core.io.registry.MarshallerRegistry; 032import org.nuxeo.ecm.core.io.registry.MarshallingException; 033import org.nuxeo.ecm.core.io.registry.Writer; 034import org.nuxeo.ecm.core.io.registry.context.RenderingContext; 035import org.nuxeo.ecm.core.io.registry.reflect.Supports; 036 037/** 038 * Base class for Json {@link Writer}. 039 * <p> 040 * This class provides a easy way to produce json and also provides the current context: {@link AbstractJsonWriter#ctx}. 041 * It provides you a {@link JsonGenerator} to manage the marshalling. 042 * </p> 043 * <p> 044 * The use of this class optimize the JsonFactory usage especially when aggregating marshallers. 045 * </p> 046 * 047 * @param <EntityType> The Java type to marshall as Json. 048 * @since 7.2 049 */ 050@Supports(APPLICATION_JSON) 051public abstract class AbstractJsonWriter<EntityType> implements Writer<EntityType> { 052 053 /** 054 * The current {@link RenderingContext}. 055 */ 056 @Inject 057 protected RenderingContext ctx; 058 059 /** 060 * The marshaller registry. 061 */ 062 @Inject 063 protected MarshallerRegistry registry; 064 065 @Override 066 public boolean accept(Class<?> clazz, Type genericType, MediaType mediatype) { 067 return true; 068 } 069 070 @Override 071 public void write(EntityType entity, Class<?> clazz, Type genericType, MediaType mediatype, OutputStream out) 072 throws IOException { 073 JsonGenerator jg = getGenerator(out, true); 074 write(entity, jg); 075 jg.flush(); 076 } 077 078 /** 079 * Implement this method to writes the entity in the provided {@link JsonGenerator}. 080 * <p> 081 * This method implementation can use injected properties. 082 * </p> 083 * <p> 084 * The {@link JsonGenerator}'s flushing is done by this abstract class, it's also not not necessary to flush it. Do 085 * not close the provided {@link JsonGenerator}. It may be used is another marshaller calling this one. 086 * </p> 087 * 088 * @param entity The entity to marshall as Json. 089 * @param jg The {@link JsonGenerator} used to produce Json output. 090 * @since 7.2 091 */ 092 public abstract void write(EntityType entity, JsonGenerator jg) throws IOException; 093 094 /** 095 * Delegates writing of an entity to the {@link MarshallerRegistry}. This will work if a Json {@link Writer} is 096 * registered in the registry for the given clazz. 097 * 098 * @param fieldName The name of the Json field in which the entity will be wrote. 099 * @param entity The entity to write. 100 * @param jg The {@link JsonGenerator} used to write the given entity. 101 * @since 7.2 102 */ 103 protected void writeEntityField(String fieldName, Object entity, JsonGenerator jg) throws IOException { 104 jg.writeFieldName(fieldName); 105 writeEntity(entity, jg); 106 } 107 108 /** 109 * Delegates writing of an entity to the {@link MarshallerRegistry}. This will work if a Json {@link Writer} is 110 * registered in the registry for the given clazz. 111 * 112 * @param entity The entity to write. 113 * @param jg The {@link JsonGenerator} used to write the given entity. 114 * @since 7.2 115 */ 116 protected void writeEntity(Object entity, JsonGenerator jg) throws IOException { 117 writeEntity(entity, new OutputStreamWithJsonWriter(jg)); 118 } 119 120 /** 121 * Delegates writing of an entity to the {@link MarshallerRegistry}. This will work if a Json {@link Writer} is 122 * registered in the registry for the given clazz. 123 * 124 * @param entity The entity to write. 125 * @param out The {@link OutputStream} in which the given entity will be wrote. 126 * @throws IOException If some i/o error append while writing entity. 127 * @since 7.2 128 */ 129 protected <ObjectType> void writeEntity(ObjectType entity, OutputStream out) throws IOException { 130 @SuppressWarnings("unchecked") 131 Class<ObjectType> clazz = (Class<ObjectType>) entity.getClass(); 132 Writer<ObjectType> writer = registry.getWriter(ctx, clazz, APPLICATION_JSON_TYPE); 133 if (writer == null) { 134 throw new MarshallingException("Unable to get a writer for Java type " + entity.getClass() 135 + " and mimetype " + APPLICATION_JSON_TYPE); 136 } 137 writer.write(entity, entity.getClass(), entity.getClass(), APPLICATION_JSON_TYPE, out); 138 } 139 140 /** 141 * Get the current Json generator or create it if none was found. 142 * 143 * @param out The {@link OutputStream} on which the generator will generate Json. 144 * @param getCurrentIfAvailable If true, try to get the current generator in the context. 145 * @return The created generator. 146 * @since 7.2 147 */ 148 protected JsonGenerator getGenerator(OutputStream out, boolean getCurrentIfAvailable) throws IOException { 149 if (getCurrentIfAvailable && out instanceof OutputStreamWithJsonWriter) { 150 OutputStreamWithJsonWriter casted = (OutputStreamWithJsonWriter) out; 151 return casted.getJsonGenerator(); 152 } 153 return JsonFactoryProvider.get().createJsonGenerator(out); 154 } 155 156}