001/* 002 * (C) Copyright 2014 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 * dmetzler 018 * Vladimir Pasquir <vpasquier@nuxeo.com> 019 */ 020package org.nuxeo.ecm.webengine; 021 022import java.io.IOException; 023 024import org.nuxeo.runtime.api.Framework; 025 026import com.fasterxml.jackson.core.JsonFactory; 027import com.fasterxml.jackson.core.JsonGenerationException; 028import com.fasterxml.jackson.core.JsonGenerator; 029import com.fasterxml.jackson.core.Version; 030import com.fasterxml.jackson.databind.BeanDescription; 031import com.fasterxml.jackson.databind.JsonSerializer; 032import com.fasterxml.jackson.databind.ObjectMapper; 033import com.fasterxml.jackson.databind.SerializationConfig; 034import com.fasterxml.jackson.databind.SerializerProvider; 035import com.fasterxml.jackson.databind.module.SimpleModule; 036import com.fasterxml.jackson.databind.ser.BeanSerializer; 037import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; 038 039/** 040 * @since 6.0 041 */ 042public class JsonFactoryManagerImpl implements JsonFactoryManager { 043 044 public static final String REST_STACK_DISPLAY = "org.nuxeo.rest.stack" + ".enable"; 045 046 protected boolean stackDisplay; 047 048 public JsonFactoryManagerImpl() { 049 stackDisplay = Framework.isBooleanPropertyTrue(REST_STACK_DISPLAY); 050 } 051 052 private static class ThrowableSerializer extends BeanSerializer { 053 054 private static final long serialVersionUID = 1L; 055 056 public ThrowableSerializer(BeanSerializer src) { 057 super(src); 058 } 059 060 @Override 061 protected void serializeFields(Object bean, JsonGenerator jgen, SerializerProvider provider) 062 throws IOException, JsonGenerationException { 063 serializeClassName(bean, jgen, provider); 064 super.serializeFields(bean, jgen, provider); 065 } 066 067 @Override 068 protected void serializeFieldsFiltered(Object bean, JsonGenerator jgen, SerializerProvider provider) 069 throws IOException, JsonGenerationException { 070 serializeClassName(bean, jgen, provider); 071 super.serializeFieldsFiltered(bean, jgen, provider); 072 } 073 074 protected void serializeClassName(Object bean, JsonGenerator jgen, SerializerProvider provider) 075 throws JsonGenerationException, IOException { 076 jgen.writeFieldName("className"); 077 jgen.writeString(bean.getClass().getName()); 078 } 079 } 080 081 private JsonFactory factory; 082 083 @Override 084 public JsonFactory getJsonFactory() { 085 if (factory == null) { 086 factory = createFactory(); 087 } 088 return factory; 089 } 090 091 @Override 092 public JsonFactory createFactory() { 093 JsonFactory factory = new JsonFactory(); 094 final ObjectMapper oc = new ObjectMapper(factory); 095 final SimpleModule module = new SimpleModule("webengine", Version.unknownVersion()) { 096 097 private static final long serialVersionUID = 1L; 098 099 @Override 100 public void setupModule(SetupContext context) { 101 super.setupModule(context); 102 103 context.addBeanSerializerModifier(new BeanSerializerModifier() { 104 105 @Override 106 public JsonSerializer<?> modifySerializer(SerializationConfig config, 107 BeanDescription beanDesc, JsonSerializer<?> serializer) { 108 if (!Throwable.class.isAssignableFrom(beanDesc.getBeanClass())) { 109 return super.modifySerializer(config, beanDesc, serializer); 110 } 111 return new ThrowableSerializer((BeanSerializer) serializer); 112 } 113 }); 114 } 115 }; 116 oc.registerModule(module); 117 factory.setCodec(oc); 118 return factory; 119 } 120 121 @Override 122 public boolean toggleStackDisplay() { 123 return stackDisplay = !stackDisplay; 124 } 125 126 @Override 127 public boolean isStackDisplay() { 128 return stackDisplay; 129 } 130}