| package org.apache.ode.bpel.obj.serde; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.lang.reflect.Field; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Vector; |
| |
| import javax.wsdl.OperationType; |
| import javax.xml.namespace.QName; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.apache.ode.bpel.obj.OProcess; |
| import org.apache.ode.bpel.obj.serde.jacksonhack.TypeBeanSerializerFactory; |
| import org.apache.ode.utils.NSContext; |
| import org.w3c.dom.Element; |
| |
| import com.fasterxml.jackson.core.JsonFactory; |
| import com.fasterxml.jackson.core.JsonParser; |
| import com.fasterxml.jackson.core.JsonProcessingException; |
| import com.fasterxml.jackson.core.JsonToken; |
| import com.fasterxml.jackson.core.io.SerializedString; |
| import com.fasterxml.jackson.databind.BeanDescription; |
| import com.fasterxml.jackson.databind.DeserializationConfig; |
| import com.fasterxml.jackson.databind.DeserializationContext; |
| import com.fasterxml.jackson.databind.JsonDeserializer; |
| import com.fasterxml.jackson.databind.ObjectMapper; |
| import com.fasterxml.jackson.databind.PropertyName; |
| import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; |
| import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer; |
| import com.fasterxml.jackson.databind.introspect.AnnotatedField; |
| import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; |
| import com.fasterxml.jackson.databind.introspect.POJOPropertyBuilder; |
| import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; |
| import com.fasterxml.jackson.databind.module.SimpleModule; |
| import com.fasterxml.jackson.databind.ser.BeanPropertyWriter; |
| import com.fasterxml.jackson.module.jaxb.deser.DomElementJsonDeserializer; |
| import com.ibm.wsdl.AbstractWSDLElement; |
| import com.ibm.wsdl.MessageImpl; |
| /** |
| * OModel Serializer that deserialize process from json using jackson. |
| * Corresponding to format {@link OmSerdeFactory.SerializeFormat#FORMAT_SERIALIZED_JSON} |
| * @see JsonOmSerializer |
| */ |
| public class JsonOmDeserializer implements OmDeserializer { |
| protected static final Log __log = LogFactory |
| .getLog(JsonOmDeserializer.class); |
| |
| private OProcess process; |
| private InputStream is; |
| |
| protected JsonFactory factory; |
| private ObjectMapper mapper; |
| private Map<Class<?>, JsonDeserializer<?>> deserializers; |
| |
| public JsonOmDeserializer() { |
| deserializers = new HashMap<Class<?>, JsonDeserializer<?>>(); |
| addCustomDeserializer(OperationType.class, |
| new OperationTypeDeserializer()); |
| addCustomDeserializer(Element.class, new DomElementDeserializerHack()); |
| addCustomDeserializer(NSContext.class, new NSContextDeserializer(NSContext.class)); |
| addCustomDeserializer(MessageImpl.class, new MessageDeserializer(MessageImpl.class)); |
| } |
| |
| public JsonOmDeserializer(InputStream is) { |
| this(is, new JsonFactory()); |
| } |
| |
| protected JsonOmDeserializer(InputStream is, JsonFactory factory) { |
| this(); |
| this.is = is; |
| this.factory = factory; |
| process = new OProcess(); |
| } |
| |
| @Override |
| @SuppressWarnings({ "unchecked", "rawtypes" }) |
| public OProcess deserialize() throws SerializaionRtException { |
| mapper = new ObjectMapper(factory); |
| mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); |
| mapper.setSerializerFactory(TypeBeanSerializerFactory.instance); |
| SimpleModule simpleModule = new SimpleModule("SimpleModule"); |
| for (Class<?> d : deserializers.keySet()) { |
| simpleModule.addDeserializer((Class) d, |
| (JsonDeserializer) deserializers.get(d)); |
| } |
| simpleModule.setDeserializerModifier(new WsdlElementDeserModifier()); |
| simpleModule.addKeyDeserializer(Object.class, new KeyAsJsonDeserializer()); |
| simpleModule.addKeyDeserializer(String.class, new KeyAsJsonDeserializer()); |
| mapper.registerModule(simpleModule); |
| |
| try { |
| process = mapper.readValue(is, OProcess.class); |
| } catch (Exception e1) { |
| SerializaionRtException e = new SerializaionRtException("Error when deseriaze process during deseriazation"); |
| e.initCause(e1); |
| throw e; |
| } |
| return process; |
| } |
| |
| public void addCustomDeserializer(Class<?> c, JsonDeserializer<?> sd) { |
| if (deserializers.containsKey(c)) { |
| __log.warn("Deserizer for type " + c |
| + " has been added. Removed previous one"); |
| } |
| deserializers.put(c, sd); |
| } |
| |
| public JsonDeserializer<?> removeCustomDeserializer(Class<?> c) { |
| return deserializers.remove(c); |
| } |
| |
| public InputStream getIs() { |
| return is; |
| } |
| |
| public void setIs(InputStream is) { |
| this.is = is; |
| } |
| |
| /** |
| * @see JsonOmSerializer.OperationTypeSerializer |
| */ |
| public static class OperationTypeDeserializer extends |
| StdScalarDeserializer<OperationType> { |
| private static final long serialVersionUID = 2015036061829834379L; |
| |
| protected OperationTypeDeserializer() { |
| super(OperationType.class); |
| } |
| |
| @Override |
| public OperationType deserialize(JsonParser jp, |
| DeserializationContext ctxt) throws IOException, |
| JsonProcessingException { |
| |
| JsonToken t = jp.getCurrentToken(); |
| if (t == JsonToken.VALUE_STRING) { |
| String text = jp.getText().trim(); |
| if ("ONE_WAY".equals(text)) { |
| return OperationType.ONE_WAY; |
| } else if ("REQUEST_RESPONSE".equals(text)) { |
| return OperationType.REQUEST_RESPONSE; |
| } else if ("SOLICIT_RESPONSE".equals(text)) { |
| return OperationType.SOLICIT_RESPONSE; |
| } else if ("NOTIFICATION".equals(text)) { |
| return OperationType.NOTIFICATION; |
| } |
| } |
| |
| throw ctxt.mappingException("Could not deserialize OperationType"); |
| } |
| |
| @Override |
| public boolean isCachable() { |
| return true; |
| } |
| } |
| |
| /** |
| * Add type info to {@link org.w3c.dom.Element}. |
| * |
| * @see DomElementJsonDeserializer |
| */ |
| public static class DomElementDeserializerHack extends DomElementJsonDeserializer{ |
| private static final long serialVersionUID = 2447322357224915181L; |
| |
| @Override |
| public Object deserializeWithType(JsonParser jp, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException { |
| boolean hadStartArray = jp.isExpectedStartArrayToken(); |
| JsonToken t = jp.nextToken(); |
| assert t == JsonToken.VALUE_STRING; |
| String type = jp.getText(); |
| assert type.equals("org.w3c.dom.Element"); |
| jp.nextToken(); |
| Object value; |
| value = deserialize(jp, ctxt); |
| if (hadStartArray && jp.nextToken() != JsonToken.END_ARRAY) { |
| throw ctxt.wrongTokenException(jp, JsonToken.END_ARRAY, |
| "expected closing END_ARRAY after type information and deserialized value"); |
| } |
| return value; |
| } |
| } |
| /** |
| * @see JsonOmSerializer.NSContextSerializer |
| */ |
| public static class NSContextDeserializer extends StdScalarDeserializer<NSContext>{ |
| private static final long serialVersionUID = -4581782525089784968L; |
| |
| protected NSContextDeserializer(Class<?> vc) { |
| super(vc); |
| } |
| |
| @Override |
| public NSContext deserialize(JsonParser jp, DeserializationContext ctxt) |
| throws IOException, JsonProcessingException { |
| @SuppressWarnings("unchecked") |
| Map<String, String> map = jp.readValueAs(Map.class); |
| NSContext ctx = new NSContext(); |
| ctx.register(map); |
| return ctx; |
| } |
| |
| } |
| |
| /** |
| * @see JsonOmSerializer.MessageSerializer |
| */ |
| public static class MessageDeserializer extends StdScalarDeserializer<MessageImpl>{ |
| |
| protected MessageDeserializer(Class<?> vc) { |
| super(vc); |
| } |
| |
| @Override |
| public MessageImpl deserialize(JsonParser jp, DeserializationContext ctxt) |
| throws IOException, JsonProcessingException { |
| MessageImpl value = new MessageImpl(); |
| value.setDocumentationElement(jp.readValueAs(Element.class)); |
| value.getExtensibilityElements().addAll(jp.readValueAs(Vector.class)); |
| value.getExtensionAttributes().putAll(jp.readValueAs(HashMap.class)); |
| |
| value.getParts().putAll(jp.readValueAs(HashMap.class)); |
| Field f1; |
| try { |
| f1 = MessageImpl.class.getDeclaredField("nativeAttributeNames"); |
| f1.setAccessible(true); |
| f1.set(value, jp.readValueAs(List.class)); |
| } catch (Exception e) { |
| __log.debug("Exception when serialize MessageImpl:" + e); |
| } |
| value.setUndefined(jp.readValueAs(Boolean.class)); |
| value.setQName(jp.readValueAs(QName.class)); |
| |
| Vector<String> parts = jp.readValueAs(Vector.class); |
| try{ |
| Field f = MessageImpl.class.getDeclaredField("additionOrderOfParts"); |
| f.setAccessible(true); |
| f.set(value, parts); |
| }catch(Exception e){ |
| __log.debug("Exception when serialize MessageImpl:" + e); |
| } |
| return value; |
| } |
| |
| } |
| |
| /** |
| * BeanDeserializerModifier to deserialize {@link AbstractWSDLElement} extensibilityElements |
| * property as field to avoid settlessProperities bug [FastXML/jackson-databind#501]. |
| */ |
| public static class WsdlElementDeserModifier extends BeanDeserializerModifier{ |
| public static class MyBeanPropertyWriter extends BeanPropertyWriter{ |
| public MyBeanPropertyWriter(BeanPropertyWriter origi, String newName){ |
| super(origi, new SerializedString(newName)); |
| } |
| } |
| @Override |
| public List<BeanPropertyDefinition> updateProperties(DeserializationConfig config, |
| BeanDescription beanDesc, |
| List<BeanPropertyDefinition> propDefs){ |
| if (!AbstractWSDLElement.class.isAssignableFrom(beanDesc.getBeanClass())) { |
| return propDefs; |
| } |
| Iterator<BeanPropertyDefinition> itor = propDefs.iterator(); |
| while(itor.hasNext()){ |
| BeanPropertyDefinition prop = itor.next(); |
| if (prop.getName().equalsIgnoreCase("extensibilityElements")){ |
| try { |
| AnnotatedField f = new AnnotatedField(AbstractWSDLElement.class.getDeclaredField("extElements"), null); |
| ((POJOPropertyBuilder)prop).addField(f, new PropertyName("extElements"), false, true, false); |
| } catch (NoSuchFieldException e) { |
| SerializaionRtException e1 = new SerializaionRtException( |
| "cann't find field, probably implementation of AbstractWSDLElement has changed"); |
| e1.initCause(e); |
| throw e1; |
| } catch (ClassCastException e){ |
| SerializaionRtException e1 = new SerializaionRtException( |
| "Cast to POJOPropertyBuilder failde, probably underlying impl of " |
| + "BeanPropertyDefinition has changed"); |
| e1.initCause(e); |
| throw e1; |
| } |
| break; |
| } |
| } |
| return propDefs; |
| } |
| } |
| } |