You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2016/02/08 18:23:53 UTC

[3/6] camel git commit: CAMEL-9576: fix deserializing proxies with mixed JDK & non-JDK interfaces

CAMEL-9576: fix deserializing proxies with mixed JDK & non-JDK interfaces


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

Branch: refs/heads/camel-2.16.x
Commit: 9bcf950fd41a3afff24816726f174b2115c48842
Parents: 0ea3ce9
Author: Lien Deboosere <le...@melexis.com>
Authored: Mon Feb 8 15:29:47 2016 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Mon Feb 8 18:23:13 2016 +0100

----------------------------------------------------------------------
 .../ClassLoadingAwareObjectInputStream.java     | 71 +++++++++++++--
 .../ClassLoadingAwareObjectInputStreamTest.java | 93 ++++++++++++++++++++
 2 files changed, 157 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/9bcf950f/components/camel-sql/src/main/java/org/apache/camel/processor/aggregate/jdbc/ClassLoadingAwareObjectInputStream.java
----------------------------------------------------------------------
diff --git a/components/camel-sql/src/main/java/org/apache/camel/processor/aggregate/jdbc/ClassLoadingAwareObjectInputStream.java b/components/camel-sql/src/main/java/org/apache/camel/processor/aggregate/jdbc/ClassLoadingAwareObjectInputStream.java
index 12535f3..80a1278 100644
--- a/components/camel-sql/src/main/java/org/apache/camel/processor/aggregate/jdbc/ClassLoadingAwareObjectInputStream.java
+++ b/components/camel-sql/src/main/java/org/apache/camel/processor/aggregate/jdbc/ClassLoadingAwareObjectInputStream.java
@@ -21,38 +21,95 @@ import java.io.InputStream;
 import java.io.ObjectInputStream;
 import java.io.ObjectStreamClass;
 import java.lang.reflect.Proxy;
+import java.util.HashMap;
 
 import org.apache.camel.CamelContext;
 
 /**
  * This class is copied from the Apache ActiveMQ project.
  */
+@SuppressWarnings("rawtypes")
 public class ClassLoadingAwareObjectInputStream extends ObjectInputStream {
 
     private CamelContext camelContext;
 
+    private static final ClassLoader FALLBACK_CLASS_LOADER =
+        ClassLoadingAwareObjectInputStream.class.getClassLoader();
+
+    /**
+     * Maps primitive type names to corresponding class objects.
+     */
+    private static final HashMap<String, Class> primClasses = new HashMap<String, Class>(8, 1.0F);
+
+    private final ClassLoader inLoader;
+
+    public ClassLoadingAwareObjectInputStream(InputStream in) throws IOException {
+        super(in);
+        inLoader = in.getClass().getClassLoader();
+    }
+
     public ClassLoadingAwareObjectInputStream(CamelContext camelContext, InputStream in) throws IOException {
         super(in);
-        this.camelContext = camelContext;
+        inLoader = camelContext.getApplicationContextClassLoader();
     }
 
-    @Override
+
     protected Class<?> resolveClass(ObjectStreamClass classDesc) throws IOException, ClassNotFoundException {
-        return camelContext.getClassResolver().resolveClass(classDesc.getName());
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        return load(classDesc.getName(), cl, inLoader);
     }
 
-    @Override
     protected Class<?> resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException {
-        Class<?>[] cinterfaces = new Class[interfaces.length];
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        Class[] cinterfaces = new Class[interfaces.length];
         for (int i = 0; i < interfaces.length; i++) {
-            cinterfaces[i] = camelContext.getClassResolver().resolveClass(interfaces[i]);
+            cinterfaces[i] = load(interfaces[i], cl);
         }
 
         try {
-            return Proxy.getProxyClass(cinterfaces[0].getClassLoader(), cinterfaces);
+            return Proxy.getProxyClass(cl, cinterfaces);
         } catch (IllegalArgumentException e) {
+            try {
+                return Proxy.getProxyClass(inLoader, cinterfaces);
+            } catch (IllegalArgumentException e1) {
+                // ignore
+            }
+            try {
+                return Proxy.getProxyClass(FALLBACK_CLASS_LOADER, cinterfaces);
+            } catch (IllegalArgumentException e2) {
+                // ignore
+            }
+
             throw new ClassNotFoundException(null, e);
         }
     }
 
+    private Class<?> load(String className, ClassLoader... cl) throws ClassNotFoundException {
+        for (ClassLoader loader : cl) {
+            try {
+                return Class.forName(className, false, loader);
+            } catch (ClassNotFoundException e) {
+                // ignore
+            }
+        }
+        // fallback
+        final Class<?> clazz = (Class<?>) primClasses.get(className);
+        if (clazz != null) {
+            return clazz;
+        } else {
+            return Class.forName(className, false, FALLBACK_CLASS_LOADER);
+        }
+    }
+
+    static {
+        primClasses.put("boolean", boolean.class);
+        primClasses.put("byte", byte.class);
+        primClasses.put("char", char.class);
+        primClasses.put("short", short.class);
+        primClasses.put("int", int.class);
+        primClasses.put("long", long.class);
+        primClasses.put("float", float.class);
+        primClasses.put("double", double.class);
+        primClasses.put("void", void.class);
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/9bcf950f/components/camel-sql/src/test/java/org/apache/camel/processor/aggregate/jdbc/ClassLoadingAwareObjectInputStreamTest.java
----------------------------------------------------------------------
diff --git a/components/camel-sql/src/test/java/org/apache/camel/processor/aggregate/jdbc/ClassLoadingAwareObjectInputStreamTest.java b/components/camel-sql/src/test/java/org/apache/camel/processor/aggregate/jdbc/ClassLoadingAwareObjectInputStreamTest.java
new file mode 100644
index 0000000..e0695ac
--- /dev/null
+++ b/components/camel-sql/src/test/java/org/apache/camel/processor/aggregate/jdbc/ClassLoadingAwareObjectInputStreamTest.java
@@ -0,0 +1,93 @@
+/**
+ * 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.processor.aggregate.jdbc;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.DefaultExchange;
+import org.apache.camel.impl.DefaultExchangeHolder;
+import org.junit.Test;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static junit.framework.Assert.assertEquals;
+
+public class ClassLoadingAwareObjectInputStreamTest {
+
+    @Test
+    public void deserialize() throws IOException, ClassNotFoundException {
+        CamelContext context = new DefaultCamelContext();
+
+        final DefaultExchange exchange = new DefaultExchange(context);
+
+        final List<MyObject> objects = new ArrayList<>();
+        final MyObject o = new MyObject("leb", "hello".getBytes());
+        objects.add(o);
+
+        exchange.getIn().setBody(objects);
+        final DefaultExchangeHolder deh = DefaultExchangeHolder.marshal(exchange);
+
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        final ObjectOutputStream oos = new ObjectOutputStream(baos);
+        oos.writeObject(deh);
+        oos.flush();
+        final byte[] serialized = baos.toByteArray();
+
+        final ObjectInputStream bis = new ClassLoadingAwareObjectInputStream(context, new ByteArrayInputStream(serialized));
+        final DefaultExchangeHolder deserialized = (DefaultExchangeHolder) bis.readObject();
+
+        final DefaultExchange exchange2 = new DefaultExchange(context);
+        DefaultExchangeHolder.unmarshal(exchange2, deserialized);
+
+        List<MyObject> receivedObjects = exchange2.getIn().getBody(List.class);
+        assertEquals(1, receivedObjects.size());
+        assertEquals(o, receivedObjects.get(0));
+    }
+
+}
+
+
+class MyObject implements Serializable {
+    final String name;
+    final byte[] content;
+
+    public MyObject(String name, byte[] content) {
+	this.name = name;
+	this.content = content;
+    }
+    
+    @Override
+    public boolean equals(Object o) {
+	if (this == o) return true;
+	if (o == null || getClass() != o.getClass()) return false;
+	
+	MyObject myObject = (MyObject) o;
+	
+	if (name != null ? !name.equals(myObject.name) : myObject.name != null) return false;
+	return Arrays.equals(content, myObject.content);	
+    }
+    
+    @Override
+    public int hashCode() {
+	int result = name != null ? name.hashCode() : 0;
+	result = 31 * result + Arrays.hashCode(content);
+	return result;
+    }
+}