/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.sesame.function;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nullable;
import com.google.common.collect.ImmutableMap;
import com.opengamma.sesame.config.EngineUtils;
import com.opengamma.util.ArgumentChecker;
/**
* Metadata for a method or constructor parameter.
*/
public final class Parameter {
private final Class<?> _declaringClass;
private final String _name;
private final ParameterType _type;
private final int _ordinal;
private final ImmutableMap<Class<?>, Annotation> _annotations;
public Parameter(Class<?> declaringClass, String name, Type genericType, int ordinal, Map<Class<?>, Annotation> annotations) {
_declaringClass = ArgumentChecker.notNull(declaringClass, "declaringClass");
_name = ArgumentChecker.notEmpty(name, "name");
_ordinal = ordinal;
_type = ParameterType.ofType(genericType);
_annotations = ImmutableMap.copyOf(ArgumentChecker.notNull(annotations, "annotations"));
}
/**
* Returns the parameter for the named constructor argument for a type.
* See {@link EngineUtils#getConstructor(Class)} for details of the constructor that will be searched.
*
* @param name the name of the constructor parameter
* @param type the type containing the constructor
* @return the parameter
* @throws IllegalArgumentException if there is no suitable constructor or no parameter with a matching name
*/
public static Parameter named(String name, Class<?> type) {
Constructor<?> constructor = EngineUtils.getConstructor(type);
for (Parameter parameter : EngineUtils.getParameters(constructor)) {
if (parameter.getName().equals(name)) {
return parameter;
}
}
throw new IllegalArgumentException("No parameters found name " + name + " in constructor " + constructor);
}
/**
* Returns a parameter on a constructor with a specified type.
* If there isn't exactly one parameter of the specified type an exception is thrown.
*
* @param parameterType the type of the parameter required
* @param constructor a constructor
* @return a parameter of the requested type
* @throws IllegalArgumentException if there isn't exactly one parameter of the specified type
*/
public static Parameter ofType(Class<?> parameterType, Constructor<?> constructor) {
List<Parameter> parameters = new ArrayList<>();
for (Parameter parameter : EngineUtils.getParameters(constructor)) {
if (parameter.getType().equals(parameterType)) {
parameters.add(parameter);
}
}
if (parameters.isEmpty()) {
throw new IllegalArgumentException("No parameters found with type " + parameterType.getName() + " in " +
"constructor " + constructor);
}
if (parameters.size() > 1) {
throw new IllegalArgumentException(parameters.size() + " parameters found with type " + parameterType.getName() +
" in constructor " + constructor);
}
return parameters.get(0);
}
public String getName() {
return _name;
}
public int getOrdinal() {
return _ordinal;
}
public Class<?> getType() {
return _type.getType();
}
public ParameterType getParameterType() {
return _type;
}
public ImmutableMap<Class<?>, Annotation> getAnnotations() {
return _annotations;
}
public Class<?> getDeclaringClass() {
return _declaringClass;
}
public boolean isNullable() {
return _annotations.get(Nullable.class) != null;
}
public String getFullName() {
return _declaringClass.getSimpleName() + "(" + _type.getName() + " " + _name + ")";
}
@Override
public String toString() {
return "Parameter [" +
"_declaringClass=" + _declaringClass +
", _name='" + _name + "'" +
", _type=" + _type +
", _ordinal=" + _ordinal +
", _annotations=" + _annotations +
"]";
}
@Override
public int hashCode() {
return Objects.hash(_declaringClass, _name, _type, _ordinal, _annotations);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Parameter other = (Parameter) obj;
return
Objects.equals(this._declaringClass, other._declaringClass) &&
Objects.equals(this._name, other._name) &&
Objects.equals(this._type, other._type) &&
Objects.equals(this._ordinal, other._ordinal) &&
Objects.equals(this._annotations, other._annotations);
}
}