You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
446 lines
13 KiB
446 lines
13 KiB
/*
|
|
* Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
package java.beans;
|
|
|
|
import com.sun.beans.TypeResolver;
|
|
|
|
import java.lang.ref.Reference;
|
|
import java.lang.ref.WeakReference;
|
|
import java.lang.ref.SoftReference;
|
|
|
|
import java.lang.reflect.Method;
|
|
|
|
import java.util.Enumeration;
|
|
import java.util.Hashtable;
|
|
import java.util.Map.Entry;
|
|
|
|
/**
|
|
* The FeatureDescriptor class is the common baseclass for PropertyDescriptor,
|
|
* EventSetDescriptor, and MethodDescriptor, etc.
|
|
* <p>
|
|
* It supports some common information that can be set and retrieved for
|
|
* any of the introspection descriptors.
|
|
* <p>
|
|
* In addition it provides an extension mechanism so that arbitrary
|
|
* attribute/value pairs can be associated with a design feature.
|
|
*/
|
|
|
|
public class FeatureDescriptor {
|
|
private static final String TRANSIENT = "transient";
|
|
|
|
private Reference<? extends Class<?>> classRef;
|
|
|
|
/**
|
|
* Constructs a <code>FeatureDescriptor</code>.
|
|
*/
|
|
public FeatureDescriptor() {
|
|
}
|
|
|
|
/**
|
|
* Gets the programmatic name of this feature.
|
|
*
|
|
* @return The programmatic name of the property/method/event
|
|
*/
|
|
public String getName() {
|
|
return name;
|
|
}
|
|
|
|
/**
|
|
* Sets the programmatic name of this feature.
|
|
*
|
|
* @param name The programmatic name of the property/method/event
|
|
*/
|
|
public void setName(String name) {
|
|
this.name = name;
|
|
}
|
|
|
|
/**
|
|
* Gets the localized display name of this feature.
|
|
*
|
|
* @return The localized display name for the property/method/event.
|
|
* This defaults to the same as its programmatic name from getName.
|
|
*/
|
|
public String getDisplayName() {
|
|
if (displayName == null) {
|
|
return getName();
|
|
}
|
|
return displayName;
|
|
}
|
|
|
|
/**
|
|
* Sets the localized display name of this feature.
|
|
*
|
|
* @param displayName The localized display name for the
|
|
* property/method/event.
|
|
*/
|
|
public void setDisplayName(String displayName) {
|
|
this.displayName = displayName;
|
|
}
|
|
|
|
/**
|
|
* The "expert" flag is used to distinguish between those features that are
|
|
* intended for expert users from those that are intended for normal users.
|
|
*
|
|
* @return True if this feature is intended for use by experts only.
|
|
*/
|
|
public boolean isExpert() {
|
|
return expert;
|
|
}
|
|
|
|
/**
|
|
* The "expert" flag is used to distinguish between features that are
|
|
* intended for expert users from those that are intended for normal users.
|
|
*
|
|
* @param expert True if this feature is intended for use by experts only.
|
|
*/
|
|
public void setExpert(boolean expert) {
|
|
this.expert = expert;
|
|
}
|
|
|
|
/**
|
|
* The "hidden" flag is used to identify features that are intended only
|
|
* for tool use, and which should not be exposed to humans.
|
|
*
|
|
* @return True if this feature should be hidden from human users.
|
|
*/
|
|
public boolean isHidden() {
|
|
return hidden;
|
|
}
|
|
|
|
/**
|
|
* The "hidden" flag is used to identify features that are intended only
|
|
* for tool use, and which should not be exposed to humans.
|
|
*
|
|
* @param hidden True if this feature should be hidden from human users.
|
|
*/
|
|
public void setHidden(boolean hidden) {
|
|
this.hidden = hidden;
|
|
}
|
|
|
|
/**
|
|
* The "preferred" flag is used to identify features that are particularly
|
|
* important for presenting to humans.
|
|
*
|
|
* @return True if this feature should be preferentially shown to human users.
|
|
*/
|
|
public boolean isPreferred() {
|
|
return preferred;
|
|
}
|
|
|
|
/**
|
|
* The "preferred" flag is used to identify features that are particularly
|
|
* important for presenting to humans.
|
|
*
|
|
* @param preferred True if this feature should be preferentially shown
|
|
* to human users.
|
|
*/
|
|
public void setPreferred(boolean preferred) {
|
|
this.preferred = preferred;
|
|
}
|
|
|
|
/**
|
|
* Gets the short description of this feature.
|
|
*
|
|
* @return A localized short description associated with this
|
|
* property/method/event. This defaults to be the display name.
|
|
*/
|
|
public String getShortDescription() {
|
|
if (shortDescription == null) {
|
|
return getDisplayName();
|
|
}
|
|
return shortDescription;
|
|
}
|
|
|
|
/**
|
|
* You can associate a short descriptive string with a feature. Normally
|
|
* these descriptive strings should be less than about 40 characters.
|
|
* @param text A (localized) short description to be associated with
|
|
* this property/method/event.
|
|
*/
|
|
public void setShortDescription(String text) {
|
|
shortDescription = text;
|
|
}
|
|
|
|
/**
|
|
* Associate a named attribute with this feature.
|
|
*
|
|
* @param attributeName The locale-independent name of the attribute
|
|
* @param value The value.
|
|
*/
|
|
public void setValue(String attributeName, Object value) {
|
|
getTable().put(attributeName, value);
|
|
}
|
|
|
|
/**
|
|
* Retrieve a named attribute with this feature.
|
|
*
|
|
* @param attributeName The locale-independent name of the attribute
|
|
* @return The value of the attribute. May be null if
|
|
* the attribute is unknown.
|
|
*/
|
|
public Object getValue(String attributeName) {
|
|
return (this.table != null)
|
|
? this.table.get(attributeName)
|
|
: null;
|
|
}
|
|
|
|
/**
|
|
* Gets an enumeration of the locale-independent names of this
|
|
* feature.
|
|
*
|
|
* @return An enumeration of the locale-independent names of any
|
|
* attributes that have been registered with setValue.
|
|
*/
|
|
public Enumeration<String> attributeNames() {
|
|
return getTable().keys();
|
|
}
|
|
|
|
/**
|
|
* Package-private constructor,
|
|
* Merge information from two FeatureDescriptors.
|
|
* The merged hidden and expert flags are formed by or-ing the values.
|
|
* In the event of other conflicts, the second argument (y) is
|
|
* given priority over the first argument (x).
|
|
*
|
|
* @param x The first (lower priority) MethodDescriptor
|
|
* @param y The second (higher priority) MethodDescriptor
|
|
*/
|
|
FeatureDescriptor(FeatureDescriptor x, FeatureDescriptor y) {
|
|
expert = x.expert | y.expert;
|
|
hidden = x.hidden | y.hidden;
|
|
preferred = x.preferred | y.preferred;
|
|
name = y.name;
|
|
shortDescription = x.shortDescription;
|
|
if (y.shortDescription != null) {
|
|
shortDescription = y.shortDescription;
|
|
}
|
|
displayName = x.displayName;
|
|
if (y.displayName != null) {
|
|
displayName = y.displayName;
|
|
}
|
|
classRef = x.classRef;
|
|
if (y.classRef != null) {
|
|
classRef = y.classRef;
|
|
}
|
|
addTable(x.table);
|
|
addTable(y.table);
|
|
}
|
|
|
|
/*
|
|
* Package-private dup constructor
|
|
* This must isolate the new object from any changes to the old object.
|
|
*/
|
|
FeatureDescriptor(FeatureDescriptor old) {
|
|
expert = old.expert;
|
|
hidden = old.hidden;
|
|
preferred = old.preferred;
|
|
name = old.name;
|
|
shortDescription = old.shortDescription;
|
|
displayName = old.displayName;
|
|
classRef = old.classRef;
|
|
|
|
addTable(old.table);
|
|
}
|
|
|
|
/**
|
|
* Copies all values from the specified attribute table.
|
|
* If some attribute is exist its value should be overridden.
|
|
*
|
|
* @param table the attribute table with new values
|
|
*/
|
|
private void addTable(Hashtable<String, Object> table) {
|
|
if ((table != null) && !table.isEmpty()) {
|
|
getTable().putAll(table);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the initialized attribute table.
|
|
*
|
|
* @return the initialized attribute table
|
|
*/
|
|
private Hashtable<String, Object> getTable() {
|
|
if (this.table == null) {
|
|
this.table = new Hashtable<>();
|
|
}
|
|
return this.table;
|
|
}
|
|
|
|
/**
|
|
* Sets the "transient" attribute according to the annotation.
|
|
* If the "transient" attribute is already set
|
|
* it should not be changed.
|
|
*
|
|
* @param annotation the annotation of the element of the feature
|
|
*/
|
|
void setTransient(Transient annotation) {
|
|
if ((annotation != null) && (null == getValue(TRANSIENT))) {
|
|
setValue(TRANSIENT, annotation.value());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Indicates whether the feature is transient.
|
|
*
|
|
* @return {@code true} if the feature is transient,
|
|
* {@code false} otherwise
|
|
*/
|
|
boolean isTransient() {
|
|
Object value = getValue(TRANSIENT);
|
|
return (value instanceof Boolean)
|
|
? (Boolean) value
|
|
: false;
|
|
}
|
|
|
|
// Package private methods for recreating the weak/soft referent
|
|
|
|
void setClass0(Class<?> cls) {
|
|
this.classRef = getWeakReference(cls);
|
|
}
|
|
|
|
Class<?> getClass0() {
|
|
return (this.classRef != null)
|
|
? this.classRef.get()
|
|
: null;
|
|
}
|
|
|
|
/**
|
|
* Creates a new soft reference that refers to the given object.
|
|
*
|
|
* @return a new soft reference or <code>null</code> if object is <code>null</code>
|
|
*
|
|
* @see SoftReference
|
|
*/
|
|
static <T> Reference<T> getSoftReference(T object) {
|
|
return (object != null)
|
|
? new SoftReference<>(object)
|
|
: null;
|
|
}
|
|
|
|
/**
|
|
* Creates a new weak reference that refers to the given object.
|
|
*
|
|
* @return a new weak reference or <code>null</code> if object is <code>null</code>
|
|
*
|
|
* @see WeakReference
|
|
*/
|
|
static <T> Reference<T> getWeakReference(T object) {
|
|
return (object != null)
|
|
? new WeakReference<>(object)
|
|
: null;
|
|
}
|
|
|
|
/**
|
|
* Resolves the return type of the method.
|
|
*
|
|
* @param base the class that contains the method in the hierarchy
|
|
* @param method the object that represents the method
|
|
* @return a class identifying the return type of the method
|
|
*
|
|
* @see Method#getGenericReturnType
|
|
* @see Method#getReturnType
|
|
*/
|
|
static Class<?> getReturnType(Class<?> base, Method method) {
|
|
if (base == null) {
|
|
base = method.getDeclaringClass();
|
|
}
|
|
return TypeResolver.erase(TypeResolver.resolveInClass(base, method.getGenericReturnType()));
|
|
}
|
|
|
|
/**
|
|
* Resolves the parameter types of the method.
|
|
*
|
|
* @param base the class that contains the method in the hierarchy
|
|
* @param method the object that represents the method
|
|
* @return an array of classes identifying the parameter types of the method
|
|
*
|
|
* @see Method#getGenericParameterTypes
|
|
* @see Method#getParameterTypes
|
|
*/
|
|
static Class<?>[] getParameterTypes(Class<?> base, Method method) {
|
|
if (base == null) {
|
|
base = method.getDeclaringClass();
|
|
}
|
|
return TypeResolver.erase(TypeResolver.resolveInClass(base, method.getGenericParameterTypes()));
|
|
}
|
|
|
|
private boolean expert;
|
|
private boolean hidden;
|
|
private boolean preferred;
|
|
private String shortDescription;
|
|
private String name;
|
|
private String displayName;
|
|
private Hashtable<String, Object> table;
|
|
|
|
/**
|
|
* Returns a string representation of the object.
|
|
*
|
|
* @return a string representation of the object
|
|
*
|
|
* @since 1.7
|
|
*/
|
|
public String toString() {
|
|
StringBuilder sb = new StringBuilder(getClass().getName());
|
|
sb.append("[name=").append(this.name);
|
|
appendTo(sb, "displayName", this.displayName);
|
|
appendTo(sb, "shortDescription", this.shortDescription);
|
|
appendTo(sb, "preferred", this.preferred);
|
|
appendTo(sb, "hidden", this.hidden);
|
|
appendTo(sb, "expert", this.expert);
|
|
if ((this.table != null) && !this.table.isEmpty()) {
|
|
sb.append("; values={");
|
|
for (Entry<String, Object> entry : this.table.entrySet()) {
|
|
sb.append(entry.getKey()).append("=").append(entry.getValue()).append("; ");
|
|
}
|
|
sb.setLength(sb.length() - 2);
|
|
sb.append("}");
|
|
}
|
|
appendTo(sb);
|
|
return sb.append("]").toString();
|
|
}
|
|
|
|
void appendTo(StringBuilder sb) {
|
|
}
|
|
|
|
static void appendTo(StringBuilder sb, String name, Reference<?> reference) {
|
|
if (reference != null) {
|
|
appendTo(sb, name, reference.get());
|
|
}
|
|
}
|
|
|
|
static void appendTo(StringBuilder sb, String name, Object value) {
|
|
if (value != null) {
|
|
sb.append("; ").append(name).append("=").append(value);
|
|
}
|
|
}
|
|
|
|
static void appendTo(StringBuilder sb, String name, boolean value) {
|
|
if (value) {
|
|
sb.append("; ").append(name);
|
|
}
|
|
}
|
|
}
|