1 package com.lexicalscope.fluentreflection;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import static ch.lambdaj.Lambda.*;
20 import static com.lexicalscope.fluentreflection.ReflectionMatcher.allOf;
21 import static com.lexicalscope.fluentreflection.ReflectionMatchers.*;
22 import static org.hamcrest.Matchers.hasItem;
23
24 import java.lang.annotation.Annotation;
25 import java.lang.reflect.ParameterizedType;
26 import java.lang.reflect.Type;
27 import java.util.List;
28
29 import org.hamcrest.Matcher;
30
31 import com.google.common.primitives.Primitives;
32 import com.google.inject.TypeLiteral;
33
34
35
36
37
38
39
40
41 class FluentClassImpl<T> implements FluentClass<T> {
42 private final ReflectedTypeFactory reflectedTypeFactory;
43 private final Class<T> klass;
44 private final ReflectedMembers<T> members;
45 private final TypeLiteral<T> typeLiteral;
46 private final FluentAnnotatedImpl annotatedElement;
47
48 FluentClassImpl(
49 final ReflectedTypeFactory reflectedTypeFactory,
50 final TypeLiteral<T> typeLiteral,
51 final ReflectedMembers<T> members) {
52 this.reflectedTypeFactory = reflectedTypeFactory;
53 this.klass = (Class<T>) typeLiteral.getRawType();
54 this.typeLiteral = typeLiteral;
55 this.members = members;
56 this.annotatedElement = new FluentAnnotatedImpl(reflectedTypeFactory, klass);
57 }
58
59 @Override public Class<T> classUnderReflection() {
60 return klass;
61 }
62
63 @Override public List<FluentMethod> methods(final Matcher<? super FluentMethod> methodMatcher) {
64 return members.methods(methodMatcher);
65 }
66
67 @Override public FluentMethod method(final Matcher<? super FluentMethod> methodMatcher) {
68 return members.method(methodMatcher);
69 }
70
71 @Override public FluentMethod method(final String name) {
72 return members.method(hasName(name));
73 }
74
75 @Override public FluentMethod staticMethod(final Matcher<? super FluentMethod> methodMatcher) {
76 return method(allOf(isStatic(), methodMatcher));
77 }
78
79 @Override public List<FluentMethod> methods() {
80 return members.methods();
81 }
82
83 @Override public List<FluentMethod> declaredMethods() {
84 return members.declaredMethods();
85 }
86
87 @Override public FluentObject<?> call(final String name, final Object ... args)
88 {
89 return call(hasName(name), args);
90 }
91
92 @SuppressWarnings("unchecked") @Override public FluentObject<?> call(
93 final Matcher<? super FluentMethod> methodMatcher,
94 final Object ... args)
95 {
96 return method(allOf(methodMatcher, canBeCalledWithArguments(args))).call(args);
97 }
98
99 @Override public List<FluentField> fields() {
100 return members.fields();
101 }
102
103 @Override public List<FluentField> fields(final ReflectionMatcher<? super FluentField> fieldMatcher) {
104 return members.fields(fieldMatcher);
105 }
106
107 @Override public FluentField field(final ReflectionMatcher<FluentMember> fieldMatcher) {
108 return members.field(fieldMatcher);
109 }
110
111 @Override public List<FluentField> declaredFields() {
112 return members.declaredFields();
113 }
114
115 @Override public List<FluentClass<?>> interfaces() {
116 return members.superclassesAndInterfaces(isAnInterface());
117 }
118
119 @Override public List<FluentClass<?>> superclasses() {
120 return members.superclassesAndInterfaces(not(isAnInterface()));
121 }
122
123 @Override public FluentClass<?> asType(final Matcher<FluentClass<?>> typeMatcher) {
124 if (typeMatcher.matches(this)) {
125 return this;
126 }
127 return selectFirst(members.superclassesAndInterfaces(), typeMatcher);
128 }
129
130 @Override public boolean isType(final ReflectionMatcher<FluentClass<?>> typeMatcher) {
131 if (typeMatcher.matches(this)) {
132 return true;
133 }
134 return hasItem(typeMatcher).matches(members.superclassesAndInterfaces());
135 }
136
137 @Override public boolean isInterface() {
138 return typeLiteral.getRawType().isInterface();
139 }
140
141 @Override public T constructRaw(final Object... args) {
142 final FluentConstructor<T> constructor =
143 constructor(hasArgumentList(convert(args, new ConvertObjectToClass())));
144
145 if (constructor == null) {
146 throw new ConstructorNotFoundRuntimeException(typeLiteral.getRawType());
147 }
148
149 return constructor.callRaw(args);
150 }
151
152 @Override public FluentObject<T> construct(final Object... args) {
153 final T newInstance = constructRaw(args);
154 return reflectedTypeFactory.reflect(typeLiteral, newInstance);
155 }
156
157 @Override public List<FluentConstructor<T>> constructors(
158 final Matcher<? super FluentConstructor<?>> constructorMatcher) {
159 return members.constructors(constructorMatcher);
160 }
161
162 @Override public FluentConstructor<T> constructor(
163 final Matcher<? super FluentConstructor<?>> constructorMatcher) {
164 return members.constructor(constructorMatcher);
165 }
166
167 @Override public boolean assignableFromObject(final Object value) {
168 return value == null
169 || klass.isAssignableFrom(value.getClass())
170 || canBeBoxed(value.getClass())
171 || canBeUnboxed(value.getClass());
172 }
173
174 @Override public boolean assignableTo(final Class<?> otherKlass) {
175 return otherKlass.isAssignableFrom(klass);
176 }
177
178 @Override public boolean canBeBoxed(final Class<?> from) {
179 return Primitives.isWrapperType(klass)
180 && Primitives.unwrap(klass).isAssignableFrom(from);
181 }
182
183 @Override public boolean canBeUnboxed(final Class<?> from) {
184 return isPrimitive()
185 && Primitives.wrap(klass).isAssignableFrom(from);
186 }
187
188 @Override public FluentClass<T> boxedType() {
189 if (isPrimitive()) {
190 return reflectedTypeFactory.reflect(Primitives.wrap(klass));
191 }
192 return this;
193 }
194
195 @Override public FluentClass<T> unboxedType() {
196 if (isUnboxable()) {
197 return reflectedTypeFactory.reflect(Primitives.unwrap(klass));
198 }
199 return this;
200 }
201
202 @Override public boolean isPrimitive() {
203 return klass.isPrimitive();
204 }
205
206 @Override public boolean isUnboxable() {
207 return Primitives.isWrapperType(klass);
208 }
209
210 @Override public FluentClass<?> typeArgument(final int typeParameter) {
211 return reflectedTypeFactory.reflect(TypeLiteral.get(((ParameterizedType) typeLiteral.getType())
212 .getActualTypeArguments()[typeParameter]));
213 }
214
215 @Override public String name() {
216 return klass.getName();
217 }
218
219 @Override public String simpleName() {
220 return klass.getSimpleName();
221 }
222
223 @Override public FluentClass<?> annotation(final Matcher<? super FluentClass<?>> annotationMatcher) {
224 return annotatedElement.annotation(annotationMatcher);
225 }
226
227 @Override public <A extends Annotation> A annotation(final Class<A> annotationClass) {
228 return annotatedElement.annotation(annotationClass);
229 }
230
231 @Override public boolean annotatedWith(final Class<? extends Annotation> annotationClass) {
232 return annotatedElement.annotatedWith(annotationClass);
233 }
234
235 @Override public boolean annotatedWith(final Matcher<? super FluentClass<?>> annotationMatcher) {
236 return annotatedElement.annotatedWith(annotationMatcher);
237 }
238
239 @Override public Type type() {
240 return typeLiteral.getType();
241 }
242
243 @Override public boolean equals(final Object that) {
244 if (that != null && that.getClass().equals(this.getClass())) {
245 return typeLiteral.equals(((FluentClassImpl<?>) that).typeLiteral);
246 }
247 return false;
248 }
249
250 @Override public int hashCode() {
251 return typeLiteral.hashCode();
252 }
253
254 @Override public String toString() {
255 return typeLiteral.toString();
256 }
257 }