/* * JBoss, Home of Professional Open Source * Copyright 2008-12, Red Hat Middleware LLC, and others contributors as indicated * by the @authors tag. All rights reserved. * See the copyright.txt in the distribution for a * full listing of individual contributors. * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License, v. 2.1. * This program is distributed in the hope that it will be useful, but WITHOUT A * 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 should have received a copy of the GNU Lesser General Public License, * v.2.1 along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package org.savara.bpmn2.model.util; import java.io.IOException; import java.lang.reflect.Method; import javax.xml.bind.JAXBElement; import org.savara.bpmn2.model.ObjectFactory; import org.savara.bpmn2.model.TActivity; import org.savara.bpmn2.model.TComplexGateway; import org.savara.bpmn2.model.TDataAssociation; import org.savara.bpmn2.model.TDataObjectReference; import org.savara.bpmn2.model.TDefinitions; import org.savara.bpmn2.model.TExclusiveGateway; import org.savara.bpmn2.model.TInclusiveGateway; import org.savara.bpmn2.model.TInputOutputBinding; import org.savara.bpmn2.model.TSequenceFlow; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.Version; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.module.SimpleModule; /** * This class provides utility functions for dealing with the JSON * representation of a BPMN2 model. * */ public class BPMN2ModelJSONUtil { private static final ObjectMapper MAPPER=new ObjectMapper(); private static final ObjectFactory FACTORY=new ObjectFactory(); static { MAPPER.enable(SerializationFeature.INDENT_OUTPUT); //MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); MAPPER.disable(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS); MAPPER.addMixInAnnotations(TActivity.class, TActivityMixIn.class); MAPPER.addMixInAnnotations(TComplexGateway.class, TComplexGatewayMixIn.class); MAPPER.addMixInAnnotations(TDataAssociation.class, TDataAssociationMixIn.class); MAPPER.addMixInAnnotations(TDataObjectReference.class, TDataObjectReferenceMixIn.class); MAPPER.addMixInAnnotations(TExclusiveGateway.class, TExclusiveGatewayMixIn.class); MAPPER.addMixInAnnotations(TInclusiveGateway.class, TInclusiveGatewayMixIn.class); MAPPER.addMixInAnnotations(TInputOutputBinding.class, TInputOutputBindingMixIn.class); MAPPER.addMixInAnnotations(TSequenceFlow.class, TSequenceFlowMixIn.class); SimpleModule testModule = new SimpleModule("BPMN2Module", new Version(1, 0, 0, null, null, null)) .addDeserializer(JAXBElement.class, new JAXBElementDeserializer()); MAPPER.registerModule(testModule); } /** * This method deserializes the JSON representation of the BPMN2 model. * * @param is The input stream * @return The BPMN2 definition * @throws IOException Failed to deserialize */ public static TDefinitions deserialize(java.io.InputStream is) throws IOException { return (MAPPER.readValue(is, TDefinitions.class)); } /** * This method serializes the BPMN2 model into a JSON representation. * * @param defns The BPMN2 model * @param os The output stream * @throws IOException Failed to serialize */ public static void serialize(TDefinitions defns, java.io.OutputStream os) throws IOException { MAPPER.writeValue(os, defns); } /** * A deserializer specifically implemented to handle the JAXBElement wrapper * around some model objects. * */ public static class JAXBElementDeserializer extends JsonDeserializer<JAXBElement<?>> { @Override public JAXBElement<?> deserialize(JsonParser jp, DeserializationContext context) throws IOException, JsonProcessingException { JAXBElement<?> ret=null; JsonNode tree=MAPPER.readTree(jp); JsonNode typeNode=tree.get("declaredType"); JsonNode valueNode=tree.get("value"); String declaredType=typeNode.asText(); try { Class<?> cls=Class.forName(declaredType); Object elem=MAPPER.convertValue(valueNode, cls); // Create JAXBElement wrapped version of the element String methodName="create"; if (cls.getSimpleName().charAt(0) == 'T') { methodName += cls.getSimpleName().substring(1); } else { methodName += cls.getSimpleName(); } Method method=ObjectFactory.class.getMethod(methodName, cls); if (method != null) { ret = (JAXBElement<?>)method.invoke(FACTORY, elem); } } catch(Exception e) { throw new IOException("Failed to deserialize object of type '"+declaredType+"'", e); } return (ret); } } abstract class TActivityMixIn { @JsonTypeInfo( use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@type") protected Object _default; } abstract class TComplexGatewayMixIn { @JsonTypeInfo( use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@type") protected Object _default; } abstract class TDataAssociationMixIn { @JsonTypeInfo( use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@type") protected Object targetRef; } abstract class TDataObjectReferenceMixIn { @JsonTypeInfo( use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@type") protected Object dataObjectRef; } abstract class TExclusiveGatewayMixIn { @JsonTypeInfo( use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@type") protected Object _default; } abstract class TInclusiveGatewayMixIn { @JsonTypeInfo( use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@type") protected Object _default; } abstract class TInputOutputBindingMixIn { @JsonTypeInfo( use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@type") protected Object inputDataRef; @JsonTypeInfo( use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@type") protected Object outputDataRef; } abstract class TSequenceFlowMixIn { @JsonTypeInfo( use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@type") protected Object sourceRef; @JsonTypeInfo( use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@type") protected Object targetRef; } }