camel-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From davscl...@apache.org
Subject camel git commit: CAMEL-9649: Do not require @XmlRootElement annotation in JAXB FallbackTypeConverter
Date Mon, 07 Mar 2016 07:34:58 GMT
Repository: camel
Updated Branches:
  refs/heads/master e6cad7c0b -> e413b9103


CAMEL-9649: Do not require @XmlRootElement annotation in JAXB FallbackTypeConverter


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/e413b910
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/e413b910
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/e413b910

Branch: refs/heads/master
Commit: e413b9103973fbab68e25376e3f5107dca9097d2
Parents: e6cad7c
Author: Martin Basovnik <mbasovni@redhat.com>
Authored: Wed Mar 2 09:31:26 2016 +0100
Committer: Claus Ibsen <davsclaus@apache.org>
Committed: Mon Mar 7 08:30:22 2016 +0100

----------------------------------------------------------------------
 .../converter/jaxb/FallbackTypeConverter.java   | 106 ++++++++++++++++---
 .../camel/converter/jaxb/message/Message.java   |  80 ++++++++++++++
 .../converter/jaxb/message/ObjectFactory.java   |  61 +++++++++++
 .../converter/jaxb/message/package-info.java    |  18 ++++
 .../jaxb/CamelJaxbFallbackConverterTest.java    |   9 ++
 5 files changed, 259 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/e413b910/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/FallbackTypeConverter.java
----------------------------------------------------------------------
diff --git a/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/FallbackTypeConverter.java
b/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/FallbackTypeConverter.java
index 9b3baac..960bfb6 100644
--- a/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/FallbackTypeConverter.java
+++ b/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/FallbackTypeConverter.java
@@ -24,13 +24,17 @@ import java.io.StringReader;
 import java.io.StringWriter;
 import java.io.UnsupportedEncodingException;
 import java.io.Writer;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
 import java.util.HashMap;
 import java.util.Map;
 
 import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.Marshaller;
 import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlElementDecl;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.stream.FactoryConfigurationError;
 import javax.xml.stream.XMLStreamException;
@@ -38,6 +42,8 @@ import javax.xml.stream.XMLStreamReader;
 import javax.xml.stream.XMLStreamWriter;
 import javax.xml.transform.Source;
 
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
 import org.apache.camel.Exchange;
 import org.apache.camel.NoTypeConversionAvailableException;
 import org.apache.camel.Processor;
@@ -55,13 +61,14 @@ import org.slf4j.LoggerFactory;
 /**
  * @version
  */
-public class FallbackTypeConverter extends ServiceSupport implements TypeConverter, TypeConverterAware
{
+public class FallbackTypeConverter extends ServiceSupport implements TypeConverter, TypeConverterAware,
CamelContextAware {
     public static final String PRETTY_PRINT = "CamelJaxbPrettyPrint"; 
     private static final Logger LOG = LoggerFactory.getLogger(FallbackTypeConverter.class);
-    private final Map<Class<?>, JAXBContext> contexts = new HashMap<Class<?>,
JAXBContext>();
+    private final Map<AnnotatedElement, JAXBContext> contexts = new HashMap<>();
     private final StaxConverter staxConverter = new StaxConverter();
     private TypeConverter parentTypeConverter;
     private boolean prettyPrint = true;
+    private CamelContext camelContext;
 
     public boolean isPrettyPrint() {
         return prettyPrint;
@@ -79,6 +86,14 @@ public class FallbackTypeConverter extends ServiceSupport implements TypeConvert
         this.parentTypeConverter = parentTypeConverter;
     }
 
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
     public <T> T convertTo(Class<T> type, Object value) {
         return convertTo(type, null, value);
     }
@@ -145,9 +160,20 @@ public class FallbackTypeConverter extends ServiceSupport implements
TypeConvert
         contexts.clear();
     }
 
+    private <T> boolean hasXmlRootElement(Class<T> type) {
+        return type.getAnnotation(XmlRootElement.class) != null;
+    }
+
     protected <T> boolean isJaxbType(Class<T> type) {
-        XmlRootElement element = type.getAnnotation(XmlRootElement.class);
-        return element != null;
+        return hasXmlRootElement(type) || (getJaxbElementFactoryMethod(type) != null);
+    }
+
+    private <T> T castJaxbType(Object o, Class<T> type) {
+        if (type.isAssignableFrom(o.getClass())) {
+            return type.cast(o);
+        } else {
+            return type.cast(((JAXBElement) o).getValue());
+        }
     }
 
     /**
@@ -169,7 +195,7 @@ public class FallbackTypeConverter extends ServiceSupport implements TypeConvert
                 if (xmlReader != null) {
                     try {
                         Object unmarshalled = unmarshal(unmarshaller, exchange, xmlReader);
-                        return type.cast(unmarshalled);
+                        return castJaxbType(unmarshalled, type);
                     } catch (Exception ex) {
                         // There is some issue on the StaxStreamReader to CXFPayload message
body with different namespaces
                         LOG.debug("Cannot use StaxStreamReader to unmarshal the message,
due to {}", ex);
@@ -179,17 +205,17 @@ public class FallbackTypeConverter extends ServiceSupport implements
TypeConvert
             InputStream inputStream = parentTypeConverter.convertTo(InputStream.class, exchange,
value);
             if (inputStream != null) {
                 Object unmarshalled = unmarshal(unmarshaller, exchange, inputStream);
-                return type.cast(unmarshalled);
+                return castJaxbType(unmarshalled, type);
             }
             Reader reader = parentTypeConverter.convertTo(Reader.class, exchange, value);
             if (reader != null) {
                 Object unmarshalled = unmarshal(unmarshaller, exchange, reader);
-                return type.cast(unmarshalled);
+                return castJaxbType(unmarshalled, type);
             }
             Source source = parentTypeConverter.convertTo(Source.class, exchange, value);
             if (source != null) {
                 Object unmarshalled = unmarshal(unmarshaller, exchange, source);
-                return type.cast(unmarshalled);
+                return castJaxbType(unmarshalled, type);
             }
         }
 
@@ -198,7 +224,7 @@ public class FallbackTypeConverter extends ServiceSupport implements TypeConvert
         }
         if (value instanceof InputStream || value instanceof Reader) {
             Object unmarshalled = unmarshal(unmarshaller, exchange, value);
-            return type.cast(unmarshalled);
+            return castJaxbType(unmarshalled, type);
         }
 
         return null;
@@ -234,17 +260,25 @@ public class FallbackTypeConverter extends ServiceSupport implements
TypeConvert
             if (exchange != null && exchange.getProperty(Exchange.CHARSET_NAME, String.class)
!= null) {
                 marshaller.setProperty(Marshaller.JAXB_ENCODING, exchange.getProperty(Exchange.CHARSET_NAME,
String.class));
             }
+            Object toMarshall = value;
+            if (!hasXmlRootElement(value.getClass())) {
+                Method m = getJaxbElementFactoryMethod(value.getClass());
+                try {
+                    toMarshall = m.invoke(getObjectFactory(value.getClass()).newInstance(),
value);
+                } catch (Exception e) {
+                    LOG.error("Unable to create JAXBElement object for type {} due to {}",
value.getClass().getName(), e);
+                }
+            }
             if (needFiltering(exchange)) {
                 XMLStreamWriter writer = parentTypeConverter.convertTo(XMLStreamWriter.class,
buffer);
                 FilteringXmlStreamWriter filteringWriter = new FilteringXmlStreamWriter(writer);
-                marshaller.marshal(value, filteringWriter);
+                marshaller.marshal(toMarshall, filteringWriter);
             } else {
-                marshaller.marshal(value, buffer);
+                marshaller.marshal(toMarshall, buffer);
             }
             // we need to pass the exchange
             answer = parentTypeConverter.convertTo(type, exchange, buffer.toString());
         }
-
         return answer;
     }
 
@@ -287,10 +321,16 @@ public class FallbackTypeConverter extends ServiceSupport implements
TypeConvert
     }
 
     protected synchronized <T> JAXBContext createContext(Class<T> type) throws
JAXBException {
-        JAXBContext context = contexts.get(type);
+        AnnotatedElement ae = hasXmlRootElement(type) ? type : type.getPackage();
+        JAXBContext context = contexts.get(ae);
         if (context == null) {
-            context = JAXBContext.newInstance(type);
-            contexts.put(type, context);
+            if (hasXmlRootElement(type)) {
+                context = JAXBContext.newInstance(type);
+                contexts.put(type, context);
+            } else {
+                context = JAXBContext.newInstance(type.getPackage().getName());
+                contexts.put(type.getPackage(), context);
+            }
         }
         return context;
     }
@@ -304,4 +344,40 @@ public class FallbackTypeConverter extends ServiceSupport implements
TypeConvert
         return !StreamCache.class.isAssignableFrom(type);
     }
 
+    private <T> Class getObjectFactory(Class<T> type) throws ClassNotFoundException
{
+        Class<?> c = null;
+        if (type.getPackage() != null) {
+            String objectFactoryClassName = type.getPackage().getName() + ".ObjectFactory";
+            c = camelContext.getClassResolver().resolveClass(objectFactoryClassName);
+        }
+        if (c == null) {
+            throw new ClassNotFoundException(String.format("ObjectFactory for type %s was
not found", type.getName()));
+        } else {
+            return c;
+        }
+    }
+
+    private <T> Method getJaxbElementFactoryMethod(Class<T> type) {
+        Method factoryMethod = null;
+        try {
+            for (Method m : getObjectFactory(type).getMethods()) {
+                final XmlElementDecl a = m.getAnnotation(XmlElementDecl.class);
+                if (a == null) {
+                    continue;
+                }
+                final Class<?>[] parameters = m.getParameterTypes();
+                if (parameters.length == 1 && parameters[0].isAssignableFrom(type))
{
+                    if (factoryMethod != null) {
+                        throw new IllegalStateException("There are several possible XML schema
mappings for class " + type.getName());
+                    } else {
+                        factoryMethod = m;
+                    }
+                }
+            }
+        } catch (ClassNotFoundException e) {
+            LOG.debug(e.getMessage(), e);
+        }
+        return factoryMethod;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e413b910/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/message/Message.java
----------------------------------------------------------------------
diff --git a/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/message/Message.java
b/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/message/Message.java
new file mode 100644
index 0000000..51be022
--- /dev/null
+++ b/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/message/Message.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.camel.converter.jaxb.message;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within
this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {"text"})
+public class Message {
+
+    @XmlElement(required = true)
+    private String text;
+
+    public Message() {
+    }
+
+    public Message(String text) {
+        this.text = text;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public void setText(String text) {
+        this.text = text;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof Message)) {
+            return false;
+        }
+        Message message = (Message) o;
+        return getText() != null ? getText().equals(message.getText()) : message.getText()
== null;
+    }
+
+    @Override
+    public int hashCode() {
+        return getText() != null ? getText().hashCode() : 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e413b910/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/message/ObjectFactory.java
----------------------------------------------------------------------
diff --git a/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/message/ObjectFactory.java
b/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/message/ObjectFactory.java
new file mode 100644
index 0000000..bc53862
--- /dev/null
+++ b/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/message/ObjectFactory.java
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.camel.converter.jaxb.message;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.annotation.XmlElementDecl;
+import javax.xml.bind.annotation.XmlRegistry;
+import javax.xml.namespace.QName;
+
+
+/**
+ * This object contains factory methods for each
+ * Java content interface and Java element interface
+ * generated in the org.apache.camel.converter.jaxb.message package.
+ * <p>An ObjectFactory allows you to programatically
+ * construct new instances of the Java representation
+ * for XML content. The Java representation of XML
+ * content can consist of schema derived interfaces
+ * and classes representing the binding of schema
+ * type definitions, element declarations and model
+ * groups.  Factory methods for each of these are
+ * provided in this class.
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+    private static final QName MESSAGE_QNAME = new QName("", "message");
+
+    /**
+     * Create a new ObjectFactory that can be used to create new instances of schema derived
classes for package: org.apache.camel.converter.jaxb.message
+     */
+    public ObjectFactory() {
+    }
+
+    /**
+     * Create an instance of {@link Message }
+     */
+    public Message createMessage() {
+        return new Message();
+    }
+
+    @XmlElementDecl(namespace = "", name = "message")
+    public JAXBElement<Message> createMessage(Message value) {
+        return new JAXBElement<>(MESSAGE_QNAME, Message.class, null, value);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e413b910/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/message/package-info.java
----------------------------------------------------------------------
diff --git a/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/message/package-info.java
b/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/message/package-info.java
new file mode 100644
index 0000000..3be7aa0
--- /dev/null
+++ b/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/message/package-info.java
@@ -0,0 +1,18 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+@javax.xml.bind.annotation.XmlSchema(namespace = "")
+package org.apache.camel.converter.jaxb.message;

http://git-wip-us.apache.org/repos/asf/camel/blob/e413b910/components/camel-jaxb/src/test/java/org/apache/camel/jaxb/CamelJaxbFallbackConverterTest.java
----------------------------------------------------------------------
diff --git a/components/camel-jaxb/src/test/java/org/apache/camel/jaxb/CamelJaxbFallbackConverterTest.java
b/components/camel-jaxb/src/test/java/org/apache/camel/jaxb/CamelJaxbFallbackConverterTest.java
index f956bad..c4559b3 100644
--- a/components/camel-jaxb/src/test/java/org/apache/camel/jaxb/CamelJaxbFallbackConverterTest.java
+++ b/components/camel-jaxb/src/test/java/org/apache/camel/jaxb/CamelJaxbFallbackConverterTest.java
@@ -22,6 +22,7 @@ import java.io.InputStream;
 import org.apache.camel.Exchange;
 import org.apache.camel.TypeConversionException;
 import org.apache.camel.TypeConverter;
+import org.apache.camel.converter.jaxb.message.Message;
 import org.apache.camel.example.Bar;
 import org.apache.camel.example.Foo;
 import org.apache.camel.foo.bar.PersonType;
@@ -115,7 +116,15 @@ public class CamelJaxbFallbackConverterTest extends CamelTestSupport
{
 
         value = converter.convertTo(String.class, exchange, person);
         assertTrue("Should not filter the non-xml chars", value.indexOf("<lastName>BAR\uD8FF</lastName>")
> 0);
+    }
 
+    @Test
+    public void testNoXmlRootElementAnnotation() throws Exception {
+        Message in = new Message("Hello World");
+        TypeConverter converter = context.getTypeConverter();
+        String marshalled = converter.convertTo(String.class, in);
+        Message out = converter.convertTo(Message.class, marshalled);
+        assertEquals(in, out);
     }
 
 }


Mime
View raw message