de.unentscheidbar.validation.internal.Beans.java Source code

Java tutorial

Introduction

Here is the source code for de.unentscheidbar.validation.internal.Beans.java

Source

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved. Portions Copyrighted 2012 Daniel
 * Huss.
 * 
 * The contents of this file are subject to the terms of either the GNU General Public License
 * Version 2 only ("GPL") or the Common Development and Distribution License("CDDL") (collectively,
 * the "License"). You may not use this file except in compliance with the License. You can obtain a
 * copy of the License at http://www.netbeans.org/cddl-gplv2.html or nbbuild/licenses/CDDL-GPL-2-CP.
 * See the License for the specific language governing permissions and limitations under the
 * License. When distributing the software, include this License Header Notice in each file and
 * include the License file at nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this particular file
 * as subject to the "Classpath" exception as provided by Sun in the GPL Version 2 section of the
 * License file that accompanied this code. If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * The Original Software is NetBeans. The Initial Developer of the Original Software is Sun
 * Microsystems, Inc. Portions Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * If you wish your version of this file to be governed by only the CDDL or only the GPL Version 2,
 * indicate your decision by adding "[Contributor] elects to include this software in this
 * distribution under the [CDDL or GPL Version 2] license." If you do not indicate a single choice
 * of license, a recipient has the option to distribute your version of this file under either the
 * CDDL, the GPL Version 2 or to extend the choice of license to its licensees as provided above.
 * However, if you add GPL Version 2 code and therefore, elected the GPL Version 2 license, then the
 * option applies only if the new code is made subject to such option by the copyright holder.
 */
package de.unentscheidbar.validation.internal;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;

import javax.annotation.Nonnull;

import org.apache.commons.lang3.ClassUtils;

import com.google.common.base.Equivalence;
import com.google.common.base.Equivalence.Wrapper;
import com.google.common.base.Throwables;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.MapMaker;

public final class Beans {

    private Beans() {

        /* Do not instantiate */
    }

    private static final Cache<Class<?>, ConcurrentMap<String, MethodHandle>> CACHE = CacheBuilder.newBuilder()
            .weakKeys().maximumSize(100).build();

    public static <T> T propertyValue(Object bean, String propertyName) {

        try {
            ConcurrentMap<String, MethodHandle> methodHandles = CACHE.get(bean.getClass(),
                    new Callable<ConcurrentMap<String, MethodHandle>>() {

                        @Override
                        public ConcurrentMap<String, MethodHandle> call() throws Exception {

                            return new MapMaker().concurrencyLevel(2).makeMap();
                        }
                    });
            /*
             * We may assume this map only grows and never shrinks. It does not matter if the same
             * getter is added twice by concurrent invocations of this method.
             */
            MethodHandle getter = methodHandles.get(propertyName);
            if (getter == null) {
                getter = getterMethod(bean.getClass(), propertyName);
                methodHandles.put(propertyName, getter);
            }
            assert getter != null;
            return (T) getter.invoke(bean);
        } catch (Throwable t) {
            throw Throwables.propagate(t);
        }
    }

    public static boolean hasReadableProperty(Class<?> beanClass, String propertyName, Class<?> returnType) {

        PropertyDescriptor pd = property(beanClass, propertyName);
        if (pd == null)
            return false;
        Method getter = pd.getReadMethod();
        return (getter != null) && ClassUtils.isAssignable(getter.getReturnType(), returnType);
    }

    public static PropertyDescriptor property(Class<?> beanClass, String propertyName) {

        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
            PropertyDescriptor[] propDescriptors = beanInfo.getPropertyDescriptors();
            if (propDescriptors == null) {
                throw new IllegalArgumentException("Class " + beanClass.getName()
                        + " does not provide property descriptors in its bean info.");
            }
            for (PropertyDescriptor pd : propDescriptors) {
                if (pd.getName().equals(propertyName)) {
                    return pd;
                }
            }
            return null;
        } catch (IntrospectionException e) {
            throw Throwables.propagate(e.getCause());
        }
    }

    public static @Nonnull MethodHandle getterMethod(Class<?> beanClass, String propertyName) {

        PropertyDescriptor pd = property(beanClass, propertyName);
        Method getter = pd == null ? null : pd.getReadMethod();
        if (getter == null) {
            throw new IllegalArgumentException("Could not find a readable property named " + propertyName
                    + " in class " + beanClass.getName());
        }
        try {
            return MethodHandles.lookup().unreflect(getter);
        } catch (IllegalAccessException e) {
            throw new IllegalArgumentException("I do not have access to property read method " + getter);
        }
    }

    public static <O> Wrapper<O> identity(O o) {

        return Equivalence.identity().wrap(o);
    }

}