de.danielbechler.diff.introspection.PropertyAccessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-object-diff Show documentation
Show all versions of java-object-diff Show documentation
Framework to detect and handle differences between Java objects
/*
* Copyright 2014 Daniel Bechler
*
* 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 de.danielbechler.diff.introspection;
import de.danielbechler.diff.access.PropertyAwareAccessor;
import de.danielbechler.diff.selector.BeanPropertyElementSelector;
import de.danielbechler.util.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import static java.util.Arrays.asList;
/**
* @author Daniel Bechler
*/
public class PropertyAccessor implements PropertyAwareAccessor
{
private static final Logger logger = LoggerFactory.getLogger(PropertyAccessor.class);
private final String propertyName;
private final Class> type;
private final Method readMethod;
private final Method writeMethod;
public PropertyAccessor(final String propertyName, final Method readMethod, final Method writeMethod)
{
Assert.notNull(propertyName, "propertyName");
Assert.notNull(readMethod, "readMethod");
this.propertyName = propertyName;
this.readMethod = makeAccessible(readMethod);
this.writeMethod = makeAccessible(writeMethod);
this.type = this.readMethod.getReturnType();
}
private static Method makeAccessible(final Method method)
{
if (method != null && !method.isAccessible())
{
logger.debug("Making method accessible: {}", method.toString());
method.setAccessible(true);
}
return method;
}
public final Set getCategoriesFromAnnotation()
{
final ObjectDiffProperty annotation = readMethod.getAnnotation(ObjectDiffProperty.class);
if (annotation != null)
{
return new TreeSet(asList(annotation.categories()));
}
return Collections.emptySet();
}
public boolean isExcludedByAnnotation()
{
final ObjectDiffProperty annotation = readMethod.getAnnotation(ObjectDiffProperty.class);
return annotation != null && annotation.excluded();
}
public String getPropertyName()
{
return this.propertyName;
}
/**
* @return The annotations of the getter used to access this property.
*/
public Set getReadMethodAnnotations()
{
return new LinkedHashSet(asList(readMethod.getAnnotations()));
}
public T getReadMethodAnnotation(final Class annotationClass)
{
final Set extends Annotation> annotations = getReadMethodAnnotations();
assert (annotations != null) : "Something is wrong here. " +
"The contract of getReadAnnotations() guarantees a non-null return value.";
for (final Annotation annotation : annotations)
{
if (annotationClass.isAssignableFrom(annotation.annotationType()))
{
return annotationClass.cast(annotation);
}
}
return null;
}
public BeanPropertyElementSelector getElementSelector()
{
return new BeanPropertyElementSelector(this.propertyName);
}
public Object get(final Object target)
{
if (target == null)
{
return null;
}
try
{
return readMethod.invoke(target);
}
catch (final Exception cause)
{
throw new PropertyReadException(propertyName, target.getClass(), cause);
}
}
public void set(final Object target, final Object value)
{
if (target == null)
{
logger.info("Couldn't set new value '{}' for property '{}' " +
"because the target object is null", value, propertyName);
}
else if (writeMethod == null)
{
logger.debug("No setter found for property '{}'", propertyName);
tryToReplaceContentOfCollectionTypes(target, value);
}
else
{
invokeWriteMethod(target, value);
}
}
public void unset(final Object target)
{
set(target, null);
}
@SuppressWarnings("unchecked")
private void tryToReplaceContentOfCollectionTypes(final Object target, final Object value)
{
if (Collection.class.isAssignableFrom(readMethod.getReturnType()))
{
if (tryToReplaceCollectionContent((Collection