Package org.eurekastreams.server.service.actions.strategies

Source Code of org.eurekastreams.server.service.actions.strategies.ReflectiveUpdater

/*
* Copyright (c) 2009-2010 Lockheed Martin Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eurekastreams.server.service.actions.strategies;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eurekastreams.commons.exceptions.ValidationException;
import org.hibernate.validator.ClassValidator;
import org.hibernate.validator.InvalidValue;

/**
* uses reflection to update an object.
*/
public class ReflectiveUpdater implements UpdaterStrategy
{

    /**
     * public constructor.
     *
     */
    public ReflectiveUpdater()
    {

    }

    /**
     * suppressing warnings here because not using generics: this is class-non-specific code.
     *
     * @param instance
     *            the object on which to set properties
     * @param properties
     *            properties to set on the instance.
     */
    public void setProperties(final Object instance, final Map<String, Serializable> properties)
    {

        PropertyDescriptor[] descriptors;
        try
        {
            descriptors = Introspector.getBeanInfo(instance.getClass()).getPropertyDescriptors();
        }
        catch (IntrospectionException ie)
        {
            // (from the javadocs)
            // Typical causes of this exception include
            // not being able to map a string class name to a Class object,
            // not being able to resolve a string method name,
            // or specifying a method name that has the wrong type signature for its intended use
            String message = "Couldn't get bean info for " + instance.getClass();
            throw new RuntimeException(message, ie);
        }

        // if there are any cast/parse exceptions, add them to this
        ValidationException validationException = new ValidationException();

        for (PropertyDescriptor property : descriptors)
        {
            // some properties might not be passed in
            String propertyName = property.getName();
            if (!properties.containsKey(propertyName))
            {
                continue;
            }

            // some properties don't have setters
            Method setter = property.getWriteMethod();
            if (setter == null)
            {
                continue;
            }

            Serializable valueObj = properties.get(propertyName);

            // catch invocation-level exceptions at the same level
            // so we only need to do exception handling once
            try
            {
                // now you have a property, a setter, and a new value. Set it!

                // to add property types, put another block here for that type
                // cast or parse exceptions are added to the ValidationException
                // and returned as part of the validation result set

                // the reason you don't just call setter.invoke() is that
                // when the map comes in as a String/String map from a form,
                // the strings will need to be parsed before calling the setter
                // if the property type is a Long/Int/Date/etc

                if (property.getPropertyType().equals(String.class))
                {
                    String value = (String) valueObj;

                    // if empty string, should set to null for database
                    // (optional=true)
                    if ("".equals(value))
                    {
                        value = null;
                    }
                    setter.invoke(instance, value);
                    continue;
                }

                if (property.getPropertyType().equals(List.class))
                {
                    setter.invoke(instance, (List) valueObj);
                    continue;
                }
                if (property.getPropertyType().equals(HashMap.class))
                {
                    setter.invoke(instance, (HashMap) valueObj);
                    continue;
                }
                if (property.getPropertyType().equals(Set.class))
                {
                    setter.invoke(instance, (Set) valueObj);
                    continue;
                }
                if (property.getPropertyType().equals(boolean.class)
                        || property.getPropertyType().equals(Boolean.class))
                {
                    setter.invoke(instance, ((Boolean) valueObj).booleanValue());
                    continue;
                }
                if (property.getPropertyType().equals(Integer.class) || property.getPropertyType().equals(int.class))
                {
                    setter.invoke(instance, (Integer) valueObj);
                    continue;
                }
                if (property.getPropertyType().equals(float.class))
                {
                    setter.invoke(instance, ((Float) valueObj).floatValue());
                    continue;
                }
                if (property.getPropertyType().equals(Date.class))
                {
                    setter.invoke(instance, (Date) valueObj);
                    continue;
                }
                // TODO add more property types here
                // once our domain classes have more than just strings.

                validationException.addError(propertyName, "Type not found.");

                // TODO some of these exceptions I either can't get to
                // (because they're programmatically prevented above)
                // or I just plain don't know how to cause. These should be tested as well
            }
            catch (IllegalArgumentException e)
            {
                validationException.addError(propertyName, valueObj + " had an illegal argument");
            }
            catch (IllegalAccessException e)
            {
                validationException.addError(propertyName, valueObj + " couldn't be accessed");
            }
            catch (InvocationTargetException e)
            {
                validationException.addError(propertyName, valueObj + " couldn't be invoked");
            }
        }

        // hibernate would throw an exception on writing,
        // but if we do it manually we can re-wrap hibernate's validation info
        // in a more concise and gwt-friendly way
        ClassValidator validator = new ClassValidator(instance.getClass());
        InvalidValue[] invalidValues = validator.getInvalidValues(instance);

        for (InvalidValue invalidValue : invalidValues)
        {
            validationException.addError(invalidValue.getPropertyName(), invalidValue.getMessage());
        }

        // throw if we had any parse errors or constraints errors
        if (validationException.getErrors().size() > 0)
        {
            throw validationException;
        }
    }
}
TOP

Related Classes of org.eurekastreams.server.service.actions.strategies.ReflectiveUpdater

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.