/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.beans;
import java.lang.ref.
Reference;
import java.lang.ref.
WeakReference;
import java.lang.reflect.
Method;
import java.util.
List;
import java.util.
ArrayList;
/**
* A MethodDescriptor describes a particular method that a Java Bean
* supports for external access from other components.
*/
public class
MethodDescriptor extends
FeatureDescriptor {
private final
MethodRef methodRef = new
MethodRef();
private
String[]
paramNames;
private
List<
WeakReference<
Class<?>>>
params;
private
ParameterDescriptor parameterDescriptors[];
/**
* Constructs a <code>MethodDescriptor</code> from a
* <code>Method</code>.
*
* @param method The low-level method information.
*/
public
MethodDescriptor(
Method method) {
this(
method, null);
}
/**
* Constructs a <code>MethodDescriptor</code> from a
* <code>Method</code> providing descriptive information for each
* of the method's parameters.
*
* @param method The low-level method information.
* @param parameterDescriptors Descriptive information for each of the
* method's parameters.
*/
public
MethodDescriptor(
Method method,
ParameterDescriptor parameterDescriptors[]) {
setName(
method.
getName());
setMethod(
method);
this.
parameterDescriptors = (
parameterDescriptors != null)
?
parameterDescriptors.
clone()
: null;
}
/**
* Gets the method that this MethodDescriptor encapsulates.
*
* @return The low-level description of the method
*/
public synchronized
Method getMethod() {
Method method = this.
methodRef.
get();
if (
method == null) {
Class<?>
cls =
getClass0();
String name =
getName();
if ((
cls != null) && (
name != null)) {
Class<?>[]
params =
getParams();
if (
params == null) {
for (int
i = 0;
i < 3;
i++) {
// Find methods for up to 2 params. We are guessing here.
// This block should never execute unless the classloader
// that loaded the argument classes disappears.
method =
Introspector.
findMethod(
cls,
name,
i, null);
if (
method != null) {
break;
}
}
} else {
method =
Introspector.
findMethod(
cls,
name,
params.length,
params);
}
setMethod(
method);
}
}
return
method;
}
private synchronized void
setMethod(
Method method) {
if (
method == null) {
return;
}
if (
getClass0() == null) {
setClass0(
method.
getDeclaringClass());
}
setParams(
getParameterTypes(
getClass0(),
method));
this.
methodRef.
set(
method);
}
private synchronized void
setParams(
Class<?>[]
param) {
if (
param == null) {
return;
}
paramNames = new
String[
param.length];
params = new
ArrayList<>(
param.length);
for (int
i = 0;
i <
param.length;
i++) {
paramNames[
i] =
param[
i].
getName();
params.
add(new
WeakReference<
Class<?>>(
param[
i]));
}
}
// pp getParamNames used as an optimization to avoid method.getParameterTypes.
String[]
getParamNames() {
return
paramNames;
}
private synchronized
Class<?>[]
getParams() {
Class<?>[]
clss = new
Class<?>[
params.
size()];
for (int
i = 0;
i <
params.
size();
i++) {
Reference<? extends
Class<?>>
ref = (
Reference<? extends
Class<?>>)
params.
get(
i);
Class<?>
cls =
ref.
get();
if (
cls == null) {
return null;
} else {
clss[
i] =
cls;
}
}
return
clss;
}
/**
* Gets the ParameterDescriptor for each of this MethodDescriptor's
* method's parameters.
*
* @return The locale-independent names of the parameters. May return
* a null array if the parameter names aren't known.
*/
public
ParameterDescriptor[]
getParameterDescriptors() {
return (this.
parameterDescriptors != null)
? this.
parameterDescriptors.
clone()
: null;
}
private static
Method resolve(
Method oldMethod,
Method newMethod) {
if (
oldMethod == null) {
return
newMethod;
}
if (
newMethod == null) {
return
oldMethod;
}
return !
oldMethod.
isSynthetic() &&
newMethod.
isSynthetic() ?
oldMethod :
newMethod;
}
/*
* Package-private constructor
* Merge two method descriptors. Where they conflict, give the
* second argument (y) priority over the first argument (x).
* @param x The first (lower priority) MethodDescriptor
* @param y The second (higher priority) MethodDescriptor
*/
MethodDescriptor(
MethodDescriptor x,
MethodDescriptor y) {
super(
x,
y);
this.
methodRef.
set(
resolve(
x.
methodRef.
get(),
y.
methodRef.
get()));
params =
x.
params;
if (
y.
params != null) {
params =
y.
params;
}
paramNames =
x.
paramNames;
if (
y.
paramNames != null) {
paramNames =
y.
paramNames;
}
parameterDescriptors =
x.
parameterDescriptors;
if (
y.
parameterDescriptors != null) {
parameterDescriptors =
y.
parameterDescriptors;
}
}
/*
* Package-private dup constructor
* This must isolate the new object from any changes to the old object.
*/
MethodDescriptor(
MethodDescriptor old) {
super(
old);
this.
methodRef.
set(
old.
getMethod());
params =
old.
params;
paramNames =
old.
paramNames;
if (
old.
parameterDescriptors != null) {
int
len =
old.
parameterDescriptors.length;
parameterDescriptors = new
ParameterDescriptor[
len];
for (int
i = 0;
i <
len ;
i++) {
parameterDescriptors[
i] = new
ParameterDescriptor(
old.
parameterDescriptors[
i]);
}
}
}
void
appendTo(
StringBuilder sb) {
appendTo(
sb, "method", this.
methodRef.
get());
if (this.
parameterDescriptors != null) {
sb.
append("; parameterDescriptors={");
for (
ParameterDescriptor pd : this.
parameterDescriptors) {
sb.
append(
pd).
append(", ");
}
sb.
setLength(
sb.
length() - 2);
sb.
append("}");
}
}
}