I was debugging JIRA-1517 when came up with the below findings. Please see
if this
is the right way to fix it or any alternatives.
>From spec:-
1) All methods from interface @Service(interfaceName/s) should be present in
the
implementation class.
2)If a Java implementation needs to realize two services with the same
interface, then this is achieved
through subclassing of the interface. The subinterface must not add any
methods. Both interfaces are
listed in the @Service annotation of the Java implementation class.
Problem:
________
Now, take for example sample-calculator, below is changed in ServiceImpl
(introduced wrong interface name)
@Service(Calculator3Service.class)
public class CalculatorServiceImpl implements CalculatorService {
Also there is an interface Calculator3Service which has String myService();
and nothing else.
Whereas CalculatorService interface has add(), subtract(), multiply(),
divide().
So 1) above is violated.
When client calls,
scaDomain = SCADomain.newInstance("Calculator.composite");
calculatorService = scaDomain.getService(CalculatorService.class,
"CalculatorServiceComponent");
calculatorService.add(3, 2);
During invokation when
org.apache.tuscany.sca.interfacedef.impl.InterfaceContractMapperImpl.map(Interface
target, Operation source)
is called, as target has only operation myService() which does not match
source, returns null and
then
org.apache.tuscany.sca.interfacedef.java.impl.JavaInterfaceUtil.findMethod()
throws NPE.
Solution:
________
To avoid this, can @Service processor be more strict and check if there is a
mismatch
in @Service(interface/s) and what is there in implements of the serviceImpl
- for the methods
in them? It may not be correct to match names of the interfaces, as in case
of rule 2) these
may not match. So, the safest way will be, in ServiceProcessor.visitClass(),
call a new method
for this check say like below and for any mismatch found
throw IllegalServiceDefinitionException("Interface "+interfaceName+" is not
implemented by " + className)
New method: in ServiceProcessor
___________
public <T> boolean checkMethodsImplemented(Class<T> clazz, Class<?>
interfaze) {
Method[] interfaceMethods = interfaze.getMethods();
Method[] classMethods = clazz.getMethods();
List <Method>classMethodsList = Arrays.asList(classMethods);
for(Method interfaceMethod : interfaceMethods) {
if(!classMethodsList.contains(interfaceMethod)) {
return false;
}
}
return true;
}
Use in: ServiceProcessor.visitClass()...
_______...............
for (Class<?> interfaze : interfaces) {
if (!interfaze.isInterface()) {
throw new InvalidServiceType("Service must be an interface", interfaze);
}
if(!checkMethodsImplemented(clazz, interfaze)) {
throw IllegalServiceDefinitionException("Interface
"+interfaze.getName()+" is not implemented by " + clazz.getName());
}
Service service;
try {
service = createService(interfaze);
} catch (InvalidInterfaceException e) {
throw new IntrospectionException(e);
}
type.getServices().add(service);
}
.........
Regards,
Amita