/* * Copyright 2012 The Solmix Project * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.gnu.org/licenses/ * or see the FSF site: http://www.fsf.org. */ package org.solmix.fmk.serialize; import java.io.IOException; import java.io.Reader; import java.io.StringWriter; import java.io.Writer; //import org.codehaus.jackson.JsonGenerationException; //import org.codehaus.jackson.Version; //import org.codehaus.jackson.map.AnnotationIntrospector; //import org.codehaus.jackson.map.JsonMappingException; //import org.codehaus.jackson.map.ObjectMapper; //import org.codehaus.jackson.map.SerializationConfig; //import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion; //import org.codehaus.jackson.map.module.SimpleModule; //import org.codehaus.jackson.xc.JaxbAnnotationIntrospector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.solmix.api.exception.SlxException; import org.solmix.api.jaxb.ObjectFactory; import org.solmix.api.jaxb.TdataSource; import org.solmix.api.jaxb.Tsolmix; import org.solmix.api.serialize.JSParser; import org.solmix.api.types.Texception; import org.solmix.api.types.Tmodule; import org.solmix.commons.util.IOUtils; import org.solmix.fmk.serialize.jackson.ContextualDateSerializer; import org.solmix.fmk.serialize.jackson.ModuleSerializer; import org.solmix.fmk.serialize.jackson.ResponseStatusSerializer; import org.solmix.fmk.serialize.jackson.TdataSourceSerializer; import org.solmix.fmk.serialize.jackson.TfieldsSerializer; import org.solmix.fmk.serialize.jackson.ToperationBindingSerializer; import org.solmix.fmk.serialize.jackson.ToperationBindingsSerializer; import org.solmix.fmk.serialize.jackson.TvalidatorsSerializer; import org.solmix.fmk.serialize.jackson.TvalueMapSerializer; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.core.JsonGenerator.Feature; import com.fasterxml.jackson.core.Version; import com.fasterxml.jackson.databind.AnnotationIntrospector; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector; /** * @author solmix.f@gmail.com * @since 0.0.1 * @version 110035 2011-2-14 solmix-ds */ public class JacksonJSParserImpl implements JSParser { private static Logger log = LoggerFactory.getLogger(JacksonJSParserImpl.class.getName()); public ObjectMapper iscMapper; public ObjectMapper mapper; public boolean prettyPrint = true; /** * @return the prettyPrint */ @Override public boolean isPrettyPrint() { return prettyPrint; } /** * @param prettyPrint the prettyPrint to set */ @Override public void setPrettyPrint(boolean prettyPrint) { this.prettyPrint = prettyPrint; } /** * @return the omitNullValues */ @Override public boolean isOmitNullValues() { return omitNullValues; } /** * @param omitNullValues the omitNullValues to set */ @Override public void setOmitNullValues(boolean omitNullValues) { this.omitNullValues = omitNullValues; } private boolean omitNullValues = true; /** * {@inheritDoc} * * @see org.solmix.api.serialize.JSParser#getImplName() */ @Override public String getImplName() { return "jackson"; } @Override public <T> T toJavaObject(Reader src, Class<T> valueType) throws SlxException { ObjectMapper mapper = initISCMapper(); try { if (log.isTraceEnabled()) { StringWriter record = new StringWriter(); IOUtils.copyCharacterStreams(src, record); log.trace("transform json: " + record.toString() + " to javaObject <" + valueType.getName() + ">"); return mapper.readValue(record.toString(), valueType); } return mapper.readValue(src, valueType); } catch (IOException e) { throw new SlxException(Tmodule.JS, Texception.IO_EXCEPTION, e); } } protected void _toIscJS(Writer out, Object obj) throws SlxException { if (obj instanceof TdataSource) { org.solmix.api.jaxb.ObjectFactory factory = new ObjectFactory(); Tsolmix module = factory.createTsolmix(); module.setDataSource((TdataSource) obj); obj = module; } ObjectMapper mapper = initISCMapper(); try { if (log.isTraceEnabled()) log.trace("transform Object Class: <" + obj.getClass().getName() + "> to JavaScript."); mapper.writeValue(out, obj); } catch (Exception ignore) { try { if (log.isTraceEnabled()) log.trace("transform js account exception try to restart the objectmapper", ignore); mapper = initISCMapper(true); mapper.writeValue(out, obj); } catch (JsonGenerationException e) { throw new SlxException(Tmodule.JS, Texception.JS_JSON_GENERATION_ERROR, e); } catch (JsonMappingException e) { throw new SlxException(Tmodule.JS, Texception.JS_JSON_MAPPING_ERROR, e); } catch (IOException e) { throw new SlxException(Texception.IO_EXCEPTION, e); } } } public ObjectMapper initISCMapper() { return initISCMapper(false); } public synchronized ObjectMapper initISCMapper(boolean restart) { if (iscMapper == null || restart) { long _s = System.currentTimeMillis(); iscMapper = new ObjectMapper(); AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(); iscMapper.getSerializationConfig().withAppendedAnnotationIntrospector(introspector); iscMapper.getSerializationConfig().withSerializationInclusion(JsonInclude.Include.NON_NULL); iscMapper = customConfig(iscMapper, true); long s_ = System.currentTimeMillis(); if (log.isDebugEnabled()) { log.debug("time used to initial jackson objectMapper:[" + (s_ - _s) + "]ms"); } } return iscMapper; } public synchronized ObjectMapper initMapper(boolean restart) { if (mapper == null || restart) { mapper = new ObjectMapper(); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL) ; mapper = customConfig(mapper, false); } return mapper; } @Override public void toJSON(Writer out, Object value) throws SlxException { if (mapper == null) initMapper(false); try { mapper.writeValue(out, value); } catch (JsonGenerationException e) { throw new SlxException(Tmodule.JS, Texception.JS_JSON_GENERATION_ERROR, e); } catch (JsonMappingException e) { throw new SlxException(Tmodule.JS, Texception.JS_JSON_MAPPING_ERROR, e); } catch (IOException e) { throw new SlxException(Texception.IO_EXCEPTION, e); } } private synchronized ObjectMapper customConfig(ObjectMapper mapper, boolean isIsc) { // if (prettyPrint) // mapper.writerWithDefaultPrettyPrinter(); if (isIsc) { SimpleModule module = new SimpleModule("SolmixJS", new Version(0, 1, 0, "alpha","org.solmix.framework","solmix-framework-datasource")); module.addSerializer(org.solmix.api.jaxb.TdataSource.class, new TdataSourceSerializer()); module.addSerializer(java.util.Date.class, new ContextualDateSerializer("new Date(", ")")); module.addSerializer(org.solmix.fmk.util.SLXDate.class, new ContextualDateSerializer("Date.parseServerDate(", ")", true)); module.addSerializer(org.solmix.api.jaxb.TvalueMap.class, new TvalueMapSerializer()); module.addSerializer(org.solmix.api.jaxb.Tvalidators.class, new TvalidatorsSerializer()); module.addSerializer(org.solmix.api.jaxb.Tfields.class, new TfieldsSerializer()); module.addSerializer(org.solmix.api.jaxb.Tsolmix.class, new ModuleSerializer()); module.addSerializer(org.solmix.api.datasource.DSResponse.Status.class, new ResponseStatusSerializer()); module.addSerializer(org.solmix.api.jaxb.ToperationBindings.class, new ToperationBindingsSerializer()); module.addSerializer(org.solmix.api.jaxb.ToperationBinding.class, new ToperationBindingSerializer()); mapper.registerModule(module); } mapper.getSerializationConfig().with(SerializationFeature.INDENT_OUTPUT); mapper.getSerializationConfig().with(SerializationFeature.FAIL_ON_EMPTY_BEANS); mapper.getSerializationConfig().without(SerializationFeature.WRITE_NULL_MAP_VALUES); mapper.getFactory().enable(Feature.AUTO_CLOSE_TARGET); if (omitNullValues) { mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL) ; } return mapper; } @Override public void toJavaScript(Writer out, Object obj) throws SlxException { _toIscJS(out, obj); } @Override public String toJavaScript(Object obj) throws SlxException { StringWriter out = new StringWriter(); toJavaScript(out, obj); return out.toString(); } /** * {@inheritDoc} * * @throws SlxException * * @see org.solmix.api.serialize.JSParser#toJavaObject(java.lang.String, java.lang.Class) */ @Override public <T> T toJavaObject(String inputString, Class<T> valueType) throws SlxException { ObjectMapper mapper = initISCMapper(); try { if (log.isTraceEnabled()) { log.trace("transform json: " + inputString + " to javaObject <" + valueType.getName() + ">"); } return mapper.readValue(inputString, valueType); } catch (IOException e) { throw new SlxException(Tmodule.JS, Texception.IO_EXCEPTION, e); } } }