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