All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.lonepulse.zombielink.util.Fields Maven / Gradle / Ivy

The newest version!
package com.lonepulse.zombielink.util;

/*
 * #%L
 * ZombieLink
 * %%
 * Copyright (C) 2013 - 2014 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 static com.lonepulse.zombielink.util.Assert.assertNotEmpty;
import static com.lonepulse.zombielink.util.Assert.assertNotNull;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * 

Fluent filtering for a collection of {@link Field}s.

* *

Note that two {@link Field}s are determined to be equal of and only if they were declared * in the same {@link Class}, using the same name and type.

* * @version 1.1.0 *

* @since 1.3.0 *

* @author Lahiru Sahan Jayasinghe */ public final class Fields implements Iterable { /** *

This contract defines a strategy for filtering the {@link Field}s within an instance * of {@link Fields} by evaluating each {@link Field} to determine if it should be included * in the filtered result.

* *

Instances of {@link Criterion} can be used via {@link Fields#filter(Criterion)}.

* * @version 1.1.0 *

* @since 1.3.0 *

* @author Lahiru Sahan Jayasinghe */ public static interface Criterion { boolean evaluate(Field field); } private List filter(Criterion criterion) { List filteredFields = new ArrayList(); for (Field field : fields) { if(criterion.evaluate(field)) { filteredFields.add(field); } } return filteredFields; } private Collection fields = null; /** *

Creates a new instance of {@link Fields} from the given object by extracting all its * member {@link Field}s.

* *

See {@link Object#getClass()} and {@link Class#getDeclaredFields()}.

* * @param target * the object whose fields are to extracted *

* @return a new instance of {@link Fields} for the {@link Field}s on the given object *

* @since 1.3.0 */ public static Fields in(Object target) { return new Fields(target.getClass().getDeclaredFields()); } /** *

Creates a new instance of {@link Fields} from the given {@link Class} by extracting * all its member {@link Field}s.

* *

See {@link Class#getDeclaredFields()}.

* * @param target * the {@link Class} whose fields are to extracted *

* @return a new instance of {@link Fields} for the {@link Field}s on the given {@link Class} *

* @since 1.3.0 */ public static Fields in(Class target) { return new Fields(target.getDeclaredFields()); } private Fields(Field[] fields) { assertNotNull(fields, Field[].class); this.fields = Collections.unmodifiableList(Arrays.asList(fields)); } private Fields(Collection fields) { assertNotNull(fields, Collection.class); this.fields = Collections.unmodifiableCollection(fields); } /** *

Filters the {@link Field}s which are annotated with the given annotation and returns a new * instance of {@link Fields} that wrap the filtered collection.

* * @param annotation * the {@link Field}s annotated with this type will be filtered *

* @return a new instance of {@link Fields} which wraps the filtered {@link Field}s *

* @since 1.3.0 */ public Fields annotatedWith(final Class annotation) { assertNotNull(annotation, Class.class); return new Fields(filter(new Criterion() { @Override public boolean evaluate(Field field) { return field.isAnnotationPresent(annotation); } })); } /** *

Filters the {@link Field}s which are annotated with all the given annotations and returns * a new instance of {@link Fields} that wrap the filtered collection.

* * @param annotation * the {@link Field}s annotated with all these types will be filtered *

* @return a new instance of {@link Fields} which wraps the filtered {@link Field}s *

* @since 1.3.0 */ public Fields annotatedWithAll(final Class... annotations) { assertNotNull(annotations, Class[].class); return new Fields(filter(new Criterion() { @Override public boolean evaluate(Field field) { boolean hasAllAnnotations = true; for (Class annotation : annotations) { if(!field.isAnnotationPresent(annotation)) { hasAllAnnotations = false; break; } } return hasAllAnnotations; } })); } /** *

Filters the {@link Field}s which are annotated with any of the given annotations and * returns a new instance of {@link Fields} that wrap the filtered collection.

* * @param annotation * the {@link Field}s annotated with any of these types will be filtered *

* @return a new instance of {@link Fields} which wraps the filtered {@link Field}s *

* @since 1.3.0 */ public Fields annotatedWithAny(final Class... annotations) { assertNotNull(annotations, Class[].class); return new Fields(filter(new Criterion() { @Override public boolean evaluate(Field field) { for (Class annotation : annotations) { if(field.isAnnotationPresent(annotation)) { return true; } } return false; } })); } /** *

Filters the {@link Field}s whose name equals (case-sensitive) the given name and returns a new * instance of {@link Fields} that wrap the filtered collection.

* * @param fieldName * the {@link Field}s having this name will be filtered *

* @return a new instance of {@link Fields} which wraps the filtered {@link Field}s *

* @since 1.3.0 */ public Fields named(final String fieldName) { assertNotEmpty(fieldName); return new Fields(filter(new Criterion() { @Override public boolean evaluate(Field field) { return field.getName().equals(fieldName); } })); } /** *

Filters the {@link Field}s whose case insensitive name equals the given name and returns * a new instance of {@link Fields} that wrap the filtered collection. * * @param fieldName * the {@link Field}s having this case insensitive name will be filtered *

* @return a new instance of {@link Fields} which wraps the filtered {@link Field}s *

* @since 1.3.0 */ public Fields strictlyNamed(final String fieldName) { assertNotEmpty(fieldName); return new Fields(filter(new Criterion() { @Override public boolean evaluate(Field field) { return field.getName().equalsIgnoreCase(fieldName); } })); } /** *

Filters the {@link Field}s whose type can be assigned to the given type and returns * a new instance of {@link Fields} that wrap the filtered collection.

* * @param type * the {@link Class} type of the {@link Field}s to be filtered *

* @return a new instance of {@link Fields} which wraps the filtered {@link Field}s *

* @since 1.3.0 */ public Fields ofType(final Class type) { assertNotEmpty(type); return new Fields(filter(new Criterion() { @Override public boolean evaluate(Field field) { return type.isAssignableFrom(field.getType()); } })); } /** *

Filters the {@link Field}s whose type equals the given type and returns a new instance * of {@link Fields} that wrap the filtered collection.

* * @param type * the {@link Class} type of the {@link Field}s to be filtered *

* @return a new instance of {@link Fields} which wraps the filtered {@link Field}s *

* @since 1.3.0 */ public Fields strictlyOfType(final Class type) { assertNotEmpty(type); return new Fields(filter(new Criterion() { @Override public boolean evaluate(Field field) { return field.getType().equals(type); } })); } /** *

Finds the difference between this instance and a supplied instance. Returns a new * instance of {@link Fields} with only those {@link Field}s which unique to this instance.

* *

	 * Difference can be expressed as, 
	 * 
	 * A - B = { x ∈ A and x ∉ B }
	 *  
	 * where,
	 * 
	 * A = this Fields instance
	 * B = supplied Fields instance
	 * x = any field from the resulting Fields instance 
	 * 

* * @param fields * the instance of {@link Fields} whose common items are subtracted from this instance *

* @return a new instance of {@link Fields} which wraps only the only those {@link Field}s which * are unique to this instance *

* @since 1.3.0 */ public Fields difference(Fields fields) { assertNotNull(fields); Set view = new HashSet(this.fields); view.removeAll(new HashSet(fields.fields)); return new Fields(view); } /** *

Finds the union between this instance and a supplied instance. Returns a new instance * of {@link Fields} which contains a set of all the {@link Field}s which in both this instance * and the supplied instance.

* *

	 * Union can be expressed as, 
	 * 
	 * A ∪ B = { x : x ∈ A or x ∈ B }
	 *  
	 * where,
	 * 
	 * A = this Fields instance
	 * B = supplied Fields instance
	 * x = any field from the resulting Fields instance 
	 * 

* * @param fields * the instance of {@link Fields} whose {@link Field}s are added to this instance *

* @return a new instance of {@link Fields} which wraps all the unique {@link Field}s in this * instance and the given instance *

* @since 1.3.0 */ public Fields union(Fields fields) { assertNotNull(fields); Set view = new HashSet(this.fields); view.addAll(new HashSet(fields.fields)); return new Fields(view); } /** *

Finds the intersection between this instance and a supplied instance. Returns a new * instance of {@link Fields} which contains all the {@link Field}s common to both instances. * *

	 * Intersection can be expressed as, 
	 * 
	 * A ∩ B = { x : x ∈ A and x ∈ B }
	 *  
	 * where,
	 * 
	 * A = this Fields instance
	 * B = supplied Fields instance
	 * x = any field from the resulting Fields instance 
	 * 

* * @param fields * the instance of {@link Fields} whose common items are discovered *

* @return a new instance of {@link Fields} which wraps only the only those {@link Field}s which * are common between this instance and the passed instance *

* @since 1.3.0 */ public Fields intersection(Fields fields) { assertNotNull(fields); Set view = new HashSet(this.fields); view.retainAll(new HashSet(fields.fields)); return new Fields(view); } /** *

Filters the {@link Field}s which match the given {@link Criterion} and returns a new instance * of {@link Fields} that wrap the filtered collection.

* * @param criterion * the {@link Criterion} whose evaluation determines the filtered field *

* @return a new instance of {@link Fields} which wraps the filtered {@link Field}s *

* @since 1.3.0 */ public Fields matching(Criterion criterion) { return new Fields(filter(criterion)); } /** *

Allows the {@link Field}s envelopped by this instance of {@link Fields} to be traversed * sequentially using the returned {@link Iterator}.

* *

Note this {@link Iterator} does not allow the underlying {@link Field}s to be modified, * for example using {@link Iterator#remove()}. Doing so will result in an * {@link UnsupportedOperationException}.

* * @return the iterator which allows the enclosed {@link Field}s to traversed sequentially *

* @since 1.3.0 */ @Override public Iterator iterator() { return this.fields.iterator(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy