/*
* Copyright (C) 2011 Red Hat, Inc. and/or its affiliates.
*
* 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 org.jboss.errai.codegen.meta;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import org.jboss.errai.codegen.util.GenUtil;
public abstract class MetaField extends AbstractHasAnnotations implements MetaClassMember {
/**
* Returns an actual MetaClass (a class, interface, primitive type, array, or
* enum, but not a type variable or a wildcard) representing an <b>erased</b>
* type that is assignable to this field.
*
* @see #getGenericType()
* @return a MetaClass representing a type that is assignable to this field.
* Never null.
*/
public abstract MetaClass getType();
/**
* Returns the actual unerased type of this field, which could be a MetaClass
* (class, enum, interface, array, primitive, etc), a bounded or unbounded
* type variable, or a wildcard. Unlike with {@link #getType()}, any type
* parameters on the field's type will be preserved in the returned MetaType
* object.
*
* @return The field type as declared. Never null.
*/
public abstract MetaType getGenericType();
/**
* Returns this field's name without any type information or qualifiers.
*
* @return The field name. Never null.
*/
@Override
public abstract String getName();
/**
* Returns the annotations present on this field.
*
* @return A shared reference to the array of the annotations on this field.
* Returns an empty array (never null) if the field has no
* annotations. Callers should refrain from modifying the returned
* array.
*/
@Override
public abstract Annotation[] getAnnotations();
/**
* Returns a string which includes the declaring class's name and the field
* type and field name, as well as all declared annotations for that field.
* Do not rely on the format of this string remaining consistent across
* releases of Errai.
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(MetaField.class.getName()).append(":");
sb.append(getDeclaringClassName()).append(".");
Annotation[] annos = getAnnotations();
if (annos != null) {
for (Annotation anno : annos) {
sb.append(anno.toString()).append(" ");
}
}
sb.append(GenUtil.scopeOf(this).getCanonicalName()).append(" ")
.append(GenUtil.modifiersOf(this).toJavaString()).append(" ")
.append(this.getType()).append(" ").append(getName());
return sb.toString();
}
private String _hashString;
/**
* Returns a string that uniquely identifies this field for purposes of
* comparison with other implementations of {@link MetaField}. The returned
* string includes the declaring class name, the field name, and the field's
* type.
*
* @return
*/
public String hashString() {
if (_hashString != null) return _hashString;
return _hashString = MetaField.class.getName()
+ ":" + getDeclaringClass().getFullyQualifiedName() + "." + getName() + "::" + getType().getFullyQualifiedName();
}
@Override
public int hashCode() {
return hashString().hashCode();
}
/**
* Compares this MetaField with another MetaField. Differing implenentations
* (for example, GWT vs Java Reflection) compare equal as long as they
* represent the same field of the same class.
*/
@Override
public boolean equals(Object o) {
return o instanceof MetaField && ((MetaField) o).hashString().equals(hashString());
}
/**
* Returns the java.lang.reflect.Field object representing this MetaField.
*
* @return The Java Reflection Field object representing the same field as
* this MetaField. Never null.
* @throws IllegalStateException
* if the field or its containing class cannot be located using Java
* Reflection.
*/
public Field asField() {
try {
final Class<?> aClass = getDeclaringClass().asClass();
return aClass.getDeclaredField(getName());
}
catch (Throwable e) {
throw new IllegalStateException(e);
}
}
/**
* Special-purpose implementation of MetaField that represents the
* {@code length} property of an array.
*/
public static class ArrayLengthMetaField extends MetaField implements HasAnnotations {
private MetaClass componentType;
public ArrayLengthMetaField(MetaClass componentType) {
this.componentType = componentType;
}
@Override
public MetaClass getType() {
return MetaClassFactory.get(int.class);
}
@Override
public MetaType getGenericType() {
return null;
}
@Override
public String getName() {
return "length";
}
@Override
public Annotation[] getAnnotations() {
return new Annotation[0];
}
@Override
public MetaClass getDeclaringClass() {
return componentType;
}
@Override
public String getDeclaringClassName() {
return componentType.getFullyQualifiedName();
}
@Override
public boolean isAbstract() {
return false;
}
@Override
public boolean isPublic() {
return true;
}
@Override
public boolean isPrivate() {
return false;
}
@Override
public boolean isProtected() {
return false;
}
@Override
public boolean isFinal() {
return false;
}
@Override
public boolean isStatic() {
return false;
}
@Override
public boolean isTransient() {
return false;
}
@Override
public boolean isSynthetic() {
return false;
}
@Override
public boolean isVolatile() {
return false;
}
@Override
public boolean isSynchronized() {
return false;
}
@Override
public boolean isAnnotationPresent(Class<? extends Annotation> annotation) {
return false;
}
@Override
public <A extends Annotation> A getAnnotation(Class<A> annotation) {
return null;
}
}
}