Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.lonepulse.icklebot.annotation;

/*
* #%L
* IckleBot
* %%
* Copyright (C) 2013 Lonepulse
* %%
* 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.
* #L%
*/

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Created by jonwillis on 8/29/13.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface IckleInherited {}
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,25 @@
* #L%
*/

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import android.app.Activity;
import android.app.Fragment;
import android.content.Context;

import com.lonepulse.icklebot.annotation.IckleInherited;
import com.lonepulse.icklebot.annotation.inject.InjectAll;
import com.lonepulse.icklebot.event.resolver.EventCategory;
import com.lonepulse.icklebot.injector.resolver.InjectionCategory;
import com.lonepulse.icklebot.injector.resolver.InjectionResolver;
import com.lonepulse.icklebot.injector.resolver.InjectionResolvers;
import com.lonepulse.icklebot.util.ContextUtils;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
* <p>This is the common contract which all injectors must implement.</p>
*
Expand Down Expand Up @@ -145,18 +146,21 @@ private Configuration(Object context) {

else
this.injectionMode = InjectionMode.EXPLICIT;

Field[] fields = context.getClass().getDeclaredFields();

InjectionResolver injectionResolver
= (this.injectionMode == InjectionMode.EXPLICIT)?
InjectionResolvers.EXPLICIT :InjectionResolvers.IMPLICIT;

for (Field field : fields) {

InjectionCategory injectionCategory = injectionResolver.resolve(context, field);
injectionTargets.get(injectionCategory).add(field);
}

Class<?> currentClass = context.getClass();

do {
Field[] fields = currentClass.getDeclaredFields();
for (Field field : fields) {
InjectionCategory injectionCategory = injectionResolver.resolve(context, field);
injectionTargets.get(injectionCategory).add(field);
}
currentClass = currentClass.getSuperclass();
} while(currentClass != null && currentClass.isAnnotationPresent(IckleInherited.class));
}

/**
Expand Down
118 changes: 61 additions & 57 deletions icklebot/src/main/java/com/lonepulse/icklebot/util/FieldUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,74 +20,78 @@
* #L%
*/

import android.app.Activity;
import android.util.Log;

import com.lonepulse.icklebot.annotation.IckleInherited;
import com.lonepulse.icklebot.injector.DuplicateInjectionException;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import android.app.Activity;
import android.util.Log;

import com.lonepulse.icklebot.injector.DuplicateInjectionException;

/**
* <p>A utility class which performs some common operations involved
* in discovering <i>{@link Field} metadata</i>.</p>
*
*
* @version 1.0.0
* <br><br>
* @author <a href="mailto:lahiru@lonepulse.com">Lahiru Sahan Jayasinghe</a>
*/
public final class FieldUtils {


/**
* <p>Constructor visibility is restricted to prevent
* <p>Constructor visibility is restricted to prevent
* nonsensical instantiation.</p>
*/
private FieldUtils() {
}


/**
* <p>Takes the {@link Activity} and discovers which of
* it's instance {@link Field}s are annotated with the given
* <p>Takes the {@link Activity} and discovers which of
* it's instance {@link Field}s are annotated with the given
* annotation (represented by supplied {@link Class}).</p>
*
* @param context
*
* @param context
* the context whose {@link Field}s are to be scanned
* <br><br>
* @param annotation
* the {@link Class} of the {@link Annotation} to look for
* <br><br>
* @return all the {@link Field}s which are <i>annotated</i> with
* @return all the {@link Field}s which are <i>annotated</i> with
* the passed {@link Annotation}
* <br><br>
* @since 1.0.0
*/
public static Set<Field> getAllFields(Object context,
Class<? extends Annotation> annotation) {

Set<Field> annotatedFields = new HashSet<Field>();

Field[] fields = context.getClass().getDeclaredFields();

for (Field field : fields) {

if(field.isAnnotationPresent(annotation)) {

annotatedFields.add(field);
}
}


Set<Field> annotatedFields = new HashSet<Field>();

Class<?> currentClass = context.getClass();

do {
Field[] fields = currentClass.getDeclaredFields();
for (Field field : fields) {
if(field.isAnnotationPresent(annotation)) {

annotatedFields.add(field);
}
}
currentClass = currentClass.getSuperclass();
} while(currentClass != null && currentClass.isAnnotationPresent(IckleInherited.class));

return annotatedFields;
}

/**
* <p>Takes the target {@link Activity} and finds the <b>only</b>
* <p>Takes the target {@link Activity} and finds the <b>only</b>
* field which is marked for injection with the given annotation.</p>
*
*
* @param context
* the context whose {@link Field}s are to be scanned
* <br><br>
Expand All @@ -103,91 +107,91 @@ public static Set<Field> getAllFields(Object context,
*/
public static Field getUniqeField(Object context,
Class<? extends Annotation> annotation) {

Set<Field> fields = FieldUtils.getAllFields(context, annotation);

if(fields.isEmpty()) {

return null;
}
else if(fields.size() > 1) {

throw new DuplicateInjectionException(context.getClass(), annotation);
}

return new ArrayList<Field>(fields).get(0);
}

/**
* <p>Takes a {@link Field} and retrieves it's value on the
* given {@link Activity} if it's type is compatible with the
* <p>Takes a {@link Field} and retrieves it's value on the
* given {@link Activity} if it's type is compatible with the
* expected type referred to by the given {@link Class}.</p>
*
* @param context
*
* @param context
* the context whose {@link Field}s are to be scanned
* <br><br>
* @param expectedType
* the {@link Class} of the field type which is <i>legal</i>
* the {@link Class} of the field type which is <i>legal</i>
* for the annotation
* <br><br>
* @param field
* the {@link Field} whose value is to be extracted
* <br><br>
* @return the value of the {@link Field}
* <br><br>
* @throws ClassCastException
* when {@link Field} value cannot be cast to the
* @throws ClassCastException
* when {@link Field} value cannot be cast to the
* expected type
* <br><br>
* @since 1.0.0
*/
public static <T extends Object> T getFieldValue(Object context,
Class<T> expectedType,
Field field) {

if (!field.isAccessible()) {

StringBuilder msg = new StringBuilder();
msg.append("Forcing accessibility for field ");
msg.append(field.getName());
msg.append(" on ");
msg.append(context.getClass().getName());
msg.append(". ");

Log.w(FieldUtils.class.getName(), msg.toString());

field.setAccessible(true);
}

Object valueObject = null;

try {

valueObject = field.get(context);
}
}
catch (IllegalArgumentException iae) {

StringBuilder msg = new StringBuilder();
msg.append("Activity ");
msg.append(context.getClass().getName());
msg.append(" is incompatible with the field ");
msg.append(field.getName());
msg.append(". ");

Log.e(FieldUtils.class.getName(), msg.toString(), iae);
}
}
catch (IllegalAccessException iae) {

StringBuilder msg = new StringBuilder();
msg.append("Field ");
msg.append(field.getName());
msg.append(" on ");
msg.append(context.getClass().getName());
msg.append(" cannot be accessed. ");

Log.e(FieldUtils.class.getName(), msg.toString(), iae);
}

return expectedType.cast(valueObject);
}
}