001 /**
002 * GRANITE DATA SERVICES
003 * Copyright (C) 2006-2013 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 package org.granite.client.messaging.codec;
021
022 import java.lang.reflect.Constructor;
023 import java.lang.reflect.Method;
024 import java.util.concurrent.ConcurrentHashMap;
025
026 import org.granite.messaging.amf.io.util.DefaultActionScriptClassDescriptor;
027 import org.granite.util.TypeUtil;
028
029 /**
030 * @author Franck WOLFF
031 */
032 public class ClientJavaClassDescriptor extends DefaultActionScriptClassDescriptor {
033
034 private static final SunConstructorFactory factory = new SunConstructorFactory();
035 private static final ConcurrentHashMap<String, Constructor<?>> constructors =
036 new ConcurrentHashMap<String, Constructor<?>>();
037
038
039 public ClientJavaClassDescriptor(String type, byte encoding) {
040 super(type, encoding);
041 }
042
043 @Override
044 public Object newJavaInstance() {
045 try {
046 return super.newJavaInstance();
047 }
048 catch (RuntimeException e) {
049 if (e.getCause() instanceof InstantiationException)
050 return findDefaultConstructor();
051 throw e;
052 }
053 }
054
055 private Object findDefaultConstructor() {
056 try {
057 Constructor<?> defaultContructor = constructors.get(type);
058 if (defaultContructor == null) {
059 defaultContructor = factory.findDefaultConstructor(TypeUtil.forName(type));
060 Constructor<?> previousConstructor = constructors.putIfAbsent(type, defaultContructor);
061 if (previousConstructor != null)
062 defaultContructor = previousConstructor; // Should be the same instance, anyway...
063 }
064 return defaultContructor.newInstance();
065 }
066 catch (Exception e) {
067 throw new RuntimeException("Could not create Proxy for: " + type);
068 }
069 }
070 }
071 class SunConstructorFactory {
072
073 private final Object reflectionFactory;
074 private final Method newConstructorForSerialization;
075
076 public SunConstructorFactory() {
077 try {
078 Class<?> factoryClass = TypeUtil.forName("sun.reflect.ReflectionFactory");
079 Method getReflectionFactory = factoryClass.getDeclaredMethod("getReflectionFactory");
080 reflectionFactory = getReflectionFactory.invoke(null);
081 newConstructorForSerialization = factoryClass.getDeclaredMethod(
082 "newConstructorForSerialization",
083 new Class[]{Class.class, Constructor.class}
084 );
085 } catch (Exception e) {
086 throw new RuntimeException("Could not create Sun Factory", e);
087 }
088 }
089
090 @SuppressWarnings("unchecked")
091 public <T> Constructor<T> findDefaultConstructor(Class<T> clazz) {
092 try {
093 Constructor<?> constructor = Object.class.getDeclaredConstructor();
094 constructor = (Constructor<?>)newConstructorForSerialization.invoke(
095 reflectionFactory,
096 new Object[]{clazz, constructor}
097 );
098 constructor.setAccessible(true);
099 return (Constructor<T>)constructor;
100 } catch (Exception e) {
101 throw new RuntimeException(e);
102 }
103 }
104 }