001/*
002 *  Copyright 2013 Christopher Pheby
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.jadira.reflection.access.portable;
017
018import java.lang.reflect.Field;
019import java.lang.reflect.Method;
020import java.util.concurrent.ConcurrentHashMap;
021
022import org.jadira.reflection.access.AbstractClassAccess;
023import org.jadira.reflection.access.api.ClassAccess;
024import org.jadira.reflection.access.api.FieldAccess;
025import org.jadira.reflection.access.api.MethodAccess;
026import org.objenesis.Objenesis;
027import org.objenesis.ObjenesisStd;
028
029/**
030 * ClassAccess implementation which should be portable across most JVMs. 
031 * Uses Reflection to access methods, and Objenesis to invoke constructors.
032 * @param <C> The Class to be accessed
033 */
034public class PortableClassAccess<C> extends AbstractClassAccess<C> implements ClassAccess<C> {
035
036    private static final ConcurrentHashMap<Class<?>, PortableClassAccess<?>> CLASS_ACCESSES = new ConcurrentHashMap<Class<?>, PortableClassAccess<?>>();
037    
038    private static final Objenesis OBJENESIS = new ObjenesisStd();
039                
040        private PortableClassAccess(Class<C> clazz) {
041                super(clazz);
042        }
043        
044        @Override
045        public C newInstance() {
046                return (C) OBJENESIS.newInstance(getType());
047        }
048
049        /**
050         * Get a new instance that can access the given Class. If the ClassAccess for this class
051         * has not been obtained before, then the specific PortableClassAccess is created by generating
052         * a specialised subclass of this class and returning it. 
053         * @param clazz Class to be accessed
054         * @param <C> The type of class
055         * @return New PortableClassAccess instance
056         */
057        public static <C> PortableClassAccess<C> get(Class<C> clazz) {
058
059        @SuppressWarnings("unchecked")
060        PortableClassAccess<C> access = (PortableClassAccess<C>) CLASS_ACCESSES.get(clazz);
061        if (access != null) {
062            return access;
063        }
064        access = new PortableClassAccess<C>(clazz);
065        CLASS_ACCESSES.putIfAbsent(clazz, access);
066        return access;
067        }
068
069        @Override
070        protected MethodAccess<C> constructMethodAccess(Method method) {
071                return PortableMethodAccess.get(method);
072        }
073        
074        @Override
075        protected FieldAccess<C> constructFieldAccess(Field field) {
076                return PortableFieldAccess.get(field);
077        }
078        
079        @Override
080        protected <X> ClassAccess<X> constructClassAccess(Class<X> clazz) {
081                return PortableClassAccess.get(clazz);
082        }
083}