001 /*
002 GRANITE DATA SERVICES
003 Copyright (C) 2012 GRANITE DATA SERVICES S.A.S.
004
005 This file is part of Granite Data Services.
006
007 Granite Data Services is free software; you can redistribute it and/or modify
008 it under the terms of the GNU Library General Public License as published by
009 the Free Software Foundation; either version 2 of the License, or (at your
010 option) any later version.
011
012 Granite Data Services is distributed in the hope that it will be useful, but
013 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015 for more details.
016
017 You should have received a copy of the GNU Library General Public License
018 along with this library; if not, see <http://www.gnu.org/licenses/>.
019 */
020
021 package org.granite.client.messaging.codec;
022
023 import java.lang.reflect.Constructor;
024 import java.lang.reflect.Method;
025 import java.util.concurrent.ConcurrentHashMap;
026
027 import org.granite.messaging.amf.io.util.DefaultActionScriptClassDescriptor;
028 import org.granite.util.TypeUtil;
029
030 /**
031 * @author Franck WOLFF
032 */
033 public class ClientJavaClassDescriptor extends DefaultActionScriptClassDescriptor {
034
035 private static final SunConstructorFactory factory = new SunConstructorFactory();
036 private static final ConcurrentHashMap<String, Constructor<?>> constructors =
037 new ConcurrentHashMap<String, Constructor<?>>();
038
039
040 public ClientJavaClassDescriptor(String type, byte encoding) {
041 super(type, encoding);
042 }
043
044 @Override
045 public Object newJavaInstance() {
046 try {
047 return super.newJavaInstance();
048 }
049 catch (RuntimeException e) {
050 if (e.getCause() instanceof InstantiationException)
051 return findDefaultConstructor();
052 throw e;
053 }
054 }
055
056 private Object findDefaultConstructor() {
057 try {
058 Constructor<?> defaultContructor = constructors.get(type);
059 if (defaultContructor == null) {
060 defaultContructor = factory.findDefaultConstructor(TypeUtil.forName(type));
061 Constructor<?> previousConstructor = constructors.putIfAbsent(type, defaultContructor);
062 if (previousConstructor != null)
063 defaultContructor = previousConstructor; // Should be the same instance, anyway...
064 }
065 return defaultContructor.newInstance();
066 }
067 catch (Exception e) {
068 throw new RuntimeException("Could not create Proxy for: " + type);
069 }
070 }
071 }
072 class SunConstructorFactory {
073
074 private final Object reflectionFactory;
075 private final Method newConstructorForSerialization;
076
077 public SunConstructorFactory() {
078 try {
079 Class<?> factoryClass = TypeUtil.forName("sun.reflect.ReflectionFactory");
080 Method getReflectionFactory = factoryClass.getDeclaredMethod("getReflectionFactory");
081 reflectionFactory = getReflectionFactory.invoke(null);
082 newConstructorForSerialization = factoryClass.getDeclaredMethod(
083 "newConstructorForSerialization",
084 new Class[]{Class.class, Constructor.class}
085 );
086 } catch (Exception e) {
087 throw new RuntimeException("Could not create Sun Factory", e);
088 }
089 }
090
091 @SuppressWarnings("unchecked")
092 public <T> Constructor<T> findDefaultConstructor(Class<T> clazz) {
093 try {
094 Constructor<?> constructor = Object.class.getDeclaredConstructor();
095 constructor = (Constructor<?>)newConstructorForSerialization.invoke(
096 reflectionFactory,
097 new Object[]{clazz, constructor}
098 );
099 constructor.setAccessible(true);
100 return (Constructor<T>)constructor;
101 } catch (Exception e) {
102 throw new RuntimeException(e);
103 }
104 }
105 }