/*
* (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Nicolas Chapurlat <nchapurlat@nuxeo.com>
*/
package org.nuxeo.ecm.core.io.marshallers.json;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Type;
import javax.inject.Inject;
import javax.ws.rs.core.MediaType;
import org.codehaus.jackson.JsonGenerator;
import org.nuxeo.ecm.core.io.registry.MarshallerRegistry;
import org.nuxeo.ecm.core.io.registry.MarshallingException;
import org.nuxeo.ecm.core.io.registry.Writer;
import org.nuxeo.ecm.core.io.registry.context.RenderingContext;
import org.nuxeo.ecm.core.io.registry.reflect.Supports;
/**
* Base class for Json {@link Writer}.
* <p>
* This class provides a easy way to produce json and also provides the current context: {@link AbstractJsonWriter#ctx}.
* It provides you a {@link JsonGenerator} to manage the marshalling.
* </p>
* <p>
* The use of this class optimize the JsonFactory usage especially when aggregating marshallers.
* </p>
*
* @param <EntityType> The Java type to marshall as Json.
* @since 7.2
*/
@Supports(APPLICATION_JSON)
public abstract class AbstractJsonWriter<EntityType> implements Writer<EntityType> {
/**
* The current {@link RenderingContext}.
*/
@Inject
protected RenderingContext ctx;
/**
* The marshaller registry.
*/
@Inject
protected MarshallerRegistry registry;
@Override
public boolean accept(Class<?> clazz, Type genericType, MediaType mediatype) {
return true;
}
@Override
public void write(EntityType entity, Class<?> clazz, Type genericType, MediaType mediatype, OutputStream out)
throws IOException {
JsonGenerator jg = getGenerator(out, true);
write(entity, jg);
jg.flush();
}
/**
* Implement this method to writes the entity in the provided {@link JsonGenerator}.
* <p>
* This method implementation can use injected properties.
* </p>
* <p>
* The {@link JsonGenerator}'s flushing is done by this abstract class, it's also not not necessary to flush it. Do
* not close the provided {@link JsonGenerator}. It may be used is another marshaller calling this one.
* </p>
*
* @param entity The entity to marshall as Json.
* @param jg The {@link JsonGenerator} used to produce Json output.
* @since 7.2
*/
public abstract void write(EntityType entity, JsonGenerator jg) throws IOException;
/**
* Delegates writing of an entity to the {@link MarshallerRegistry}. This will work if a Json {@link Writer} is
* registered in the registry for the given clazz.
*
* @param fieldName The name of the Json field in which the entity will be wrote.
* @param entity The entity to write.
* @param jg The {@link JsonGenerator} used to write the given entity.
* @since 7.2
*/
protected void writeEntityField(String fieldName, Object entity, JsonGenerator jg) throws IOException {
jg.writeFieldName(fieldName);
writeEntity(entity, jg);
}
/**
* Delegates writing of an entity to the {@link MarshallerRegistry}. This will work if a Json {@link Writer} is
* registered in the registry for the given clazz.
*
* @param entity The entity to write.
* @param jg The {@link JsonGenerator} used to write the given entity.
* @since 7.2
*/
protected void writeEntity(Object entity, JsonGenerator jg) throws IOException {
writeEntity(entity, new OutputStreamWithJsonWriter(jg));
}
/**
* Delegates writing of an entity to the {@link MarshallerRegistry}. This will work if a Json {@link Writer} is
* registered in the registry for the given clazz.
*
* @param entity The entity to write.
* @param out The {@link OutputStream} in which the given entity will be wrote.
* @throws IOException If some i/o error append while writing entity.
* @since 7.2
*/
protected <ObjectType> void writeEntity(ObjectType entity, OutputStream out) throws IOException {
@SuppressWarnings("unchecked")
Class<ObjectType> clazz = (Class<ObjectType>) entity.getClass();
Writer<ObjectType> writer = registry.getWriter(ctx, clazz, APPLICATION_JSON_TYPE);
if (writer == null) {
throw new MarshallingException("Unable to get a writer for Java type " + entity.getClass()
+ " and mimetype " + APPLICATION_JSON_TYPE);
}
writer.write(entity, entity.getClass(), entity.getClass(), APPLICATION_JSON_TYPE, out);
}
/**
* Get the current Json generator or create it if none was found.
*
* @param out The {@link OutputStream} on which the generator will generate Json.
* @param getCurrentIfAvailable If true, try to get the current generator in the context.
* @return The created generator.
* @since 7.2
*/
protected JsonGenerator getGenerator(OutputStream out, boolean getCurrentIfAvailable) throws IOException {
if (getCurrentIfAvailable && out instanceof OutputStreamWithJsonWriter) {
OutputStreamWithJsonWriter casted = (OutputStreamWithJsonWriter) out;
return casted.getJsonGenerator();
}
return JsonFactoryProvider.get().createJsonGenerator(out);
}
}