in modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceIntrospectorImpl.java [208:365]
private <T> List<Operation> getOperations(Class<T> clazz,
boolean remotable,
String ns) throws InvalidInterfaceException {
Set<Type> genericInterfaces = new HashSet<Type>();
collectGenericInterfaces(clazz, genericInterfaces);
Map<String, Type> typeBindings = new HashMap<String, Type>();
for (Type genericInterface : genericInterfaces) {
if (genericInterface instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType)genericInterface;
TypeVariable<?>[] typeVariables = ((Class<?>)parameterizedType.getRawType()).getTypeParameters();
Type[] typeArguments = parameterizedType.getActualTypeArguments();
for (int i = 0; i < typeArguments.length; i++) {
typeBindings.put(typeVariables[i].getName(), typeArguments[i]);
}
}
}
boolean isAsyncService = clazz.isAnnotationPresent(AsyncInvocation.class);
Method[] methods = clazz.getMethods();
List<Operation> operations = new ArrayList<Operation>(methods.length);
Set<String> names = remotable ? new HashSet<String>() : null;
for (Method method : methods) {
boolean hasMultipleOutputs = false;
if (method.getDeclaringClass() == Object.class) {
// Skip the methods on the Object.class
continue;
}
String name = method.getName();
Class<?> lastParameter = method.getParameterTypes().length > 0 ? method.getParameterTypes()[method.getParameterTypes().length-1] : null;
boolean isAsyncMethod = isAsyncService && name.endsWith("Async") && lastParameter != null && ResponseDispatch.class.equals(lastParameter);
if (isAsyncMethod) {
name = name.substring(0, name.length()-5);
}
if (remotable && names.contains(name)) {
throw new OverloadedOperationException(method);
}
if (remotable && !jaxwsAsyncMethod(method)) {
names.add(name);
}
Class<?>[] parameterTypes = getActualTypes(method.getGenericParameterTypes(), method.getParameterTypes(), typeBindings, isAsyncMethod);
Class<?> returnType;
if (isAsyncMethod) {
ParameterizedType t = (ParameterizedType)method.getGenericParameterTypes()[method.getGenericParameterTypes().length-1];
returnType = (Class<?>)t.getActualTypeArguments()[0];
} else {
returnType = getActualType(method.getGenericReturnType(), method.getReturnType(), typeBindings);
}
Class<?>[] faultTypes =
getActualTypes(method.getGenericExceptionTypes(), method.getExceptionTypes(), typeBindings, false);
Class<?>[] allOutputTypes = getOutputTypes(returnType, parameterTypes);
// For async server interfaces, faults are described using the @AsyncFaults annotation
if( method.isAnnotationPresent(AsyncFault.class) ) {
faultTypes = readAsyncFaultTypes( method );
} // end if
boolean nonBlocking = method.isAnnotationPresent(OneWay.class);
if (nonBlocking) {
if (!(returnType == void.class)) {
throw new InvalidOperationException(
"Method should return 'void' when declared with an @OneWay annotation. " + method,
method);
}
if (!(faultTypes.length == 0)) {
throw new InvalidOperationException(
"Method should not declare exceptions with an @OneWay annotation. " + method,
method);
}
}
JavaOperation operation = new JavaOperationImpl();
operation.setName(name);
// Given details of Holder mapping, it's easier to handle output first.
List<DataType> outputDataTypes = new ArrayList<DataType>();
XMLType xmlReturnType = new XMLType(new QName(ns, "return"), null);
DataType<XMLType> returnDataType = null;
if (returnType == void.class) {
operation.setReturnTypeVoid(true);
} else {
if (isAsyncMethod) {
returnDataType = new DataTypeImpl<XMLType>(UNKNOWN_DATABINDING, returnType, returnType, xmlReturnType);
} else {
returnDataType = new DataTypeImpl<XMLType>(UNKNOWN_DATABINDING, returnType, method.getGenericReturnType(), xmlReturnType);
}
operation.setReturnTypeVoid(false);
outputDataTypes.add(returnDataType);
}
// Handle Input Types
List<DataType> paramDataTypes = new ArrayList<DataType>(parameterTypes.length);
Type[] genericParamTypes = method.getGenericParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
Class<?> paramType = parameterTypes[i];
XMLType xmlParamType = new XMLType(new QName(ns, "arg" + i), null);
DataTypeImpl<XMLType> xmlDataType = new DataTypeImpl<XMLType>(
UNKNOWN_DATABINDING, paramType, genericParamTypes[i],xmlParamType);
ParameterMode mode = ParameterMode.IN;
// Holder pattern. Physical types of Holder<T> classes are updated to <T> to aid in transformations.
if ( Holder.class == paramType) {
hasMultipleOutputs = true;
Type firstActual = getFirstActualType( genericParamTypes[ i ] );
if ( firstActual != null ) {
xmlDataType.setPhysical( (Class<?>)firstActual );
mode = ParameterMode.INOUT;
}
outputDataTypes.add(xmlDataType);
}
paramDataTypes.add( xmlDataType);
operation.getParameterModes().add(mode);
}
// Fault types
List<DataType> faultDataTypes = new ArrayList<DataType>(faultTypes.length);
Type[] genericFaultTypes = method.getGenericExceptionTypes();
if( method.isAnnotationPresent(AsyncFault.class) ) {
genericFaultTypes = readAsyncGenericFaultTypes( method );
} // end if
for (int i = 0; i < faultTypes.length; i++) {
Class<?> faultType = faultTypes[i];
// Only add checked exceptions
// JAXWS Specification v2.1 section 3.7 says RemoteException should not be mapped
if (Exception.class.isAssignableFrom(faultType) && (!RuntimeException.class.isAssignableFrom(faultType))
&& (!RemoteException.class.isAssignableFrom(faultType))) {
XMLType xmlFaultType = new XMLType(new QName(ns, faultType.getSimpleName()), null);
DataType<XMLType> faultDataType =
new DataTypeImpl<XMLType>(UNKNOWN_DATABINDING, faultType, genericFaultTypes[i], xmlFaultType);
faultDataTypes.add(new DataTypeImpl<DataType>(UNKNOWN_DATABINDING, faultType, genericFaultTypes[i],
faultDataType));
}
}
DataType<List<DataType>> inputType =
new DataTypeImpl<List<DataType>>(IDL_INPUT, Object[].class, paramDataTypes);
DataType<List<DataType>> outputType =
new DataTypeImpl<List<DataType>>(IDL_OUTPUT, Object[].class, outputDataTypes);
operation.setOutputType(outputType);
operation.setInputType(inputType);
operation.setFaultTypes(faultDataTypes);
operation.setNonBlocking(nonBlocking);
operation.setJavaMethod(method);
operation.setHasArrayWrappedOutput(hasMultipleOutputs);
operation.setAsyncServer(isAsyncMethod);
operations.add(operation);
}
return operations;
}