package com.lexicalscope.fluentreflection;
import static com.lexicalscope.fluentreflection.ReflectionMatcher.allOf;
import static com.lexicalscope.fluentreflection.ReflectionMatchers.*;
import static org.hamcrest.Matchers.hasItem;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import org.hamcrest.Matcher;
import com.google.common.primitives.Primitives;
import com.google.inject.TypeLiteral;
/*
* Copyright 2012 Tim Wood
*
* 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.
*/
public abstract class AbstractFluentAccess<T> implements FluentAccess<T> {
protected final FluentAnnotatedImpl annotatedElement;
protected final Class<T> klass;
protected final ReflectedMembers<T> members;
protected final ReflectedTypeFactory reflectedTypeFactory;
protected final TypeLiteral<T> typeLiteral;
AbstractFluentAccess(
final ReflectedTypeFactory reflectedTypeFactory,
final TypeLiteral<T> typeLiteral,
final ReflectedMembers<T> members) {
this.reflectedTypeFactory = reflectedTypeFactory;
this.klass = (Class<T>) typeLiteral.getRawType();
this.typeLiteral = typeLiteral;
this.members = members;
this.annotatedElement = new FluentAnnotatedImpl(reflectedTypeFactory, klass);
}
@Override public boolean annotatedWith(final Class<? extends Annotation> annotationClass) {
return annotatedElement.annotatedWith(annotationClass);
}
@Override public boolean annotatedWith(final Matcher<? super FluentAccess<?>> annotationMatcher) {
return annotatedElement.annotatedWith(annotationMatcher);
}
@Override public <A extends Annotation> A annotation(final Class<A> annotationClass) {
return annotatedElement.annotation(annotationClass);
}
@Override public FluentClass<?> annotation(final Matcher<? super FluentClass<?>> annotationMatcher) {
return annotatedElement.annotation(annotationMatcher);
}
@Override public boolean assignableFrom(final Class<?> otherKlass) {
return klass.isAssignableFrom(otherKlass);
}
@Override public boolean assignableFromObject(final Object value) {
return value == null
|| klass.isAssignableFrom(value.getClass())
|| canBeBoxed(value.getClass())
|| canBeUnboxed(value.getClass());
}
@Override public boolean assignableTo(final Class<?> otherKlass) {
return otherKlass.isAssignableFrom(klass);
}
@Override public FluentObject<?> call(
final Matcher<? super FluentMember> methodMatcher,
final Object ... args)
{
return member(allOf(methodMatcher, canBeCalledWithArguments(args))).call(args);
}
@Override public FluentObject<?> call(final String name, final Object ... args)
{
return call(hasName(name), args);
}
@Override public boolean canBeBoxed(final Class<?> from) {
return Primitives.isWrapperType(klass)
&& Primitives.unwrap(klass).isAssignableFrom(from);
}
@Override public boolean canBeUnboxed(final Class<?> from) {
return isPrimitive()
&& Primitives.wrap(klass).isAssignableFrom(from);
}
@Override public Class<T> classUnderReflection() {
return klass;
}
@Override public List<FluentField> declaredFields() {
return members.declaredFields();
}
@Override public List<FluentMethod> declaredMethods() {
return members.declaredMethods();
}
@Override public FluentField field(final Matcher<? super FluentMember> fieldMatcher) {
return members.field(fieldMatcher);
}
@Override public FluentField field(final String fieldName) {
return field(hasName(fieldName));
}
@Override public List<FluentField> fields() {
return members.fields();
}
@Override public List<FluentField> fields(final Matcher<? super FluentField> fieldMatcher) {
return members.fields(fieldMatcher);
}
@Override public List<FluentClass<?>> interfaces() {
return members.superclassesAndInterfaces(isAnInterface());
}
@Override public boolean isInterface() {
return typeLiteral.getRawType().isInterface();
}
@Override public boolean isPrimitive() {
return klass.isPrimitive();
}
@Override public boolean isType(final Matcher<? super FluentClass<?>> typeMatcher) {
if (typeMatcher.matches(this)) {
return true;
}
return hasItem(typeMatcher).matches(members.superclassesAndInterfaces());
}
@Override public boolean isUnboxable() {
return Primitives.isWrapperType(klass);
}
@Override public FluentMethod method(final Matcher<? super FluentMethod> methodMatcher) {
return members.method(methodMatcher);
}
@Override public FluentMethod method(final String name) {
return members.method(hasName(name));
}
@Override public List<FluentMethod> methods() {
return members.methods();
}
@Override public List<FluentMethod> methods(final Matcher<? super FluentMethod> methodMatcher) {
return members.methods(methodMatcher);
}
@Override public String name() {
return klass.getName();
}
@Override public String simpleName() {
return klass.getSimpleName();
}
@Override public List<FluentClass<?>> superclasses() {
return members.superclassesAndInterfaces(not(isAnInterface()));
}
@Override public Type type() {
return typeLiteral.getType();
}
@Override public FluentClass<?> typeArgument(final int typeParameter) {
return reflectedTypeFactory.reflect(TypeLiteral.get(((ParameterizedType) typeLiteral.getType())
.getActualTypeArguments()[typeParameter]));
}
@Override public FluentMember member(final Matcher<? super FluentMember> memberMatcher) {
return members.member(memberMatcher);
}
}