001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.util; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.io.ObjectInputStream; 022import java.io.ObjectStreamClass; 023import java.lang.reflect.InvocationHandler; 024import java.lang.reflect.Proxy; 025import java.util.HashMap; 026 027/** 028 * This class is copied from the Apache ActiveMQ project. 029 */ 030@SuppressWarnings("rawtypes") 031public class ClassLoadingAwareObjectInputStream extends ObjectInputStream { 032 033 private static final ClassLoader FALLBACK_CLASS_LOADER = ClassLoadingAwareObjectInputStream.class.getClassLoader(); 034 035 /** 036 * Maps primitive type names to corresponding class objects. 037 */ 038 private static final HashMap<String, Class> PRIM_CLASSES = new HashMap<>(8, 1.0F); 039 040 private final ClassLoader inLoader; 041 042 public ClassLoadingAwareObjectInputStream(InputStream in) throws IOException { 043 super(in); 044 inLoader = in.getClass().getClassLoader(); 045 } 046 047 public ClassLoadingAwareObjectInputStream(ClassLoader classLoader, InputStream in) throws IOException { 048 super(in); 049 if (classLoader != null) { 050 inLoader = classLoader; 051 } else { 052 inLoader = in.getClass().getClassLoader(); 053 } 054 } 055 056 @Override 057 protected Class<?> resolveClass(ObjectStreamClass classDesc) throws IOException, ClassNotFoundException { 058 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 059 return load(classDesc.getName(), cl, inLoader); 060 } 061 062 /** 063 * We only need to retrieve the proxy class, an invocation is not supposed to happen but let's handle primitives to 064 * avoid potential NPE 065 */ 066 private static final InvocationHandler NOOP_HANDLER = (proxy, method, args) -> { 067 Class<?> returnType = method.getReturnType(); 068 if (returnType == void.class) { 069 return null; 070 } else if (returnType.isPrimitive()) { 071 if (returnType == boolean.class) 072 return Boolean.FALSE; 073 if (returnType == byte.class) 074 return (byte) 0; 075 if (returnType == short.class) 076 return (short) 0; 077 if (returnType == int.class) 078 return 0; 079 if (returnType == long.class) 080 return 0L; 081 if (returnType == float.class) 082 return 0.0f; 083 if (returnType == double.class) 084 return 0.0d; 085 if (returnType == char.class) 086 return '\0'; 087 } 088 return null; 089 }; 090 091 @Override 092 protected Class<?> resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException { 093 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 094 Class[] cinterfaces = new Class[interfaces.length]; 095 for (int i = 0; i < interfaces.length; i++) { 096 cinterfaces[i] = load(interfaces[i], cl); 097 } 098 099 try { 100 return Proxy.newProxyInstance(cl, cinterfaces, NOOP_HANDLER).getClass(); 101 } catch (IllegalArgumentException e) { 102 try { 103 return Proxy.newProxyInstance(inLoader, cinterfaces, NOOP_HANDLER).getClass(); 104 } catch (IllegalArgumentException e1) { 105 // ignore 106 } 107 try { 108 return Proxy.newProxyInstance(FALLBACK_CLASS_LOADER, cinterfaces, NOOP_HANDLER) 109 .getClass(); 110 } catch (IllegalArgumentException e2) { 111 // ignore 112 } 113 114 throw new ClassNotFoundException(null, e); 115 } 116 } 117 118 private Class<?> load(String className, ClassLoader... cl) throws ClassNotFoundException { 119 for (ClassLoader loader : cl) { 120 try { 121 return Class.forName(className, false, loader); 122 } catch (ClassNotFoundException e) { 123 // ignore 124 } 125 } 126 // fallback 127 final Class<?> clazz = PRIM_CLASSES.get(className); 128 if (clazz != null) { 129 return clazz; 130 } else { 131 return Class.forName(className, false, FALLBACK_CLASS_LOADER); 132 } 133 } 134 135 static { 136 PRIM_CLASSES.put("boolean", boolean.class); 137 PRIM_CLASSES.put("byte", byte.class); 138 PRIM_CLASSES.put("char", char.class); 139 PRIM_CLASSES.put("short", short.class); 140 PRIM_CLASSES.put("int", int.class); 141 PRIM_CLASSES.put("long", long.class); 142 PRIM_CLASSES.put("float", float.class); 143 PRIM_CLASSES.put("double", double.class); 144 PRIM_CLASSES.put("void", void.class); 145 } 146}