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

net.derquinse.common.meta.MetaClassBuilder Maven / Gradle / Ivy

Go to download

Module containing support classes depending on Java SE 6, Guava 11 and Joda-Time 2.0

There is a newer version: 1.0.37
Show newest version
/*
 * Copyright (C) the original author or authors.
 *
 * 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 net.derquinse.common.meta;

import static com.google.common.base.Preconditions.checkNotNull;
import static net.derquinse.common.meta.MetaClass.ROOT;

import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Modifier;

import net.derquinse.common.base.Builder;

import com.google.common.collect.ImmutableList;
import com.google.common.reflect.TypeToken;

/**
 * Meta class descriptor builder.
 * @author Andres Rodriguez
 * @param  Described type.
 */
public final class MetaClassBuilder implements Builder> {
	/** Described type. */
	private final TypeToken type;
	/** Super class. */
	private final MetaClass superclass;
	/** Super interfaces. */
	private final ImmutableList> superinterfaces;
	/** Declared field map. */
	private final FieldMap declaredFields;
	/** All field map. */
	private final FieldMap fields;

	private static boolean publicStaticFinal(Member m) {
		int modifiers = m.getModifiers();
		return Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers);
	}

	/**
	 * Default constructor.
	 */
	MetaClassBuilder(TypeToken type) {
		this.type = checkNotNull(type, "The described type is mandatory");
		// Discover the class
		// 1 - Superclass
		Class raw = type.getRawType();
		this.superclass = getSuper(raw.getSuperclass());
		ImmutableList.Builder> builder = ImmutableList.builder();
		// 2 - Superinterfaces
		for (Class i : raw.getInterfaces()) {
			MetaClass meta = getSuper(i);
			if (meta != ROOT) {
				builder.add(meta);
			}
		}
		this.superinterfaces = builder.build();
		// 3 - Declared fields
		ImmutableFieldMap.Builder fieldBuilder = ImmutableFieldMap.builder();
		for (Field f : raw.getDeclaredFields()) {
			// We get public static final MetaFields that are type compatible.
			if (publicStaticFinal(f)) {
				Object val;
				try {
					val = f.get(null);
				} catch (Exception e) {
					throw new IllegalArgumentException(String.format("Unable to get value of type [%s] field [%s]", type,
							f.getName()), e);
				}
				if (val instanceof MetaField) {
					MetaField mf = MetaField.class.cast(val);
					if (mf.getEnclosingType().isAssignableFrom(type)) {
						// Checked in the if
						@SuppressWarnings("unchecked")
						MetaField smf = (MetaField) mf;
						fieldBuilder.add(smf);
					}
				}
			}
		}
		this.declaredFields = fieldBuilder.build();
		// 4 - All fields
		ImmutableFieldMap.Builder fmap = ImmutableFieldMap.builder();
		fmap.addAll(this.superclass.getFields());
		for (MetaClass mi : this.superinterfaces) {
			fmap.addAll(mi.getFields());
		}
		if (fmap.isEmpty()) {
			this.fields = declaredFields;
		} else {
			fmap.addAll(declaredFields);
			this.fields = fmap.build();
		}
	}

	/** Returns the metaclass for the superclass or a superinterface. */
	@SuppressWarnings("unchecked")
	private MetaClass getSuper(Class klass) {
		if (klass == null || !WithMetaClass.class.isAssignableFrom(klass)) {
			return ROOT;
		}
		// We know what we are doing
		return (MetaClass) MetaClass.of(klass.asSubclass(WithMetaClass.class));
	}

	/** Returns the described type. */
	public TypeToken getType() {
		return type;
	}

	/** Returns the supermetaclass. */
	public MetaClass getSuperclass() {
		return superclass;
	}

	/** Returns the superinterfaces. */
	public ImmutableList> getSuperinterfaces() {
		return superinterfaces;
	}

	/** Returns the declared field map. */
	public FieldMap getDeclaredFields() {
		return declaredFields;
	}

	/** Returns the all fields map. */
	public FieldMap getFields() {
		return fields;
	}

	/**
	 * Builds the meta class. If there was a previous metaclass registered for the same type, that one
	 * is returned.
	 */
	public MetaClass build() {
		try {
			return new MetaClass(this);
		} catch (DuplicateMetaClassException e) {
			// Trusted
			@SuppressWarnings("unchecked")
			MetaClass metaClass = (MetaClass) e.getMetaClass();
			return metaClass;
		}
	}

	@Override
	public String toString() {
		return Metas.toStringHelper(this).toString();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy