Some SWORD updates

February 19, 2009

Being an aggregate of bits and pieces associated with the SWORD protocol: –

  • A quick note to clear up a common confusion I encountered last week at the JISC developer days: The JISC-funded project “SWORD2” led to the 1.3 version of the spec. There is no “SWORD 2.0” spec.
  • I’ve put my mercurial repository of the SWORD spec on bitbucket. This is mainly in the interests of transparency, rather than because I think anyone will be interested.
  • Mark Nottingham’s recent blog post on the evil of experimental HTTP headers points out that the headers we used in SWORD should be changed. We hadn’t read enough RFCs, clearly! I’m in the process of working out what needs to be done to register headers and change the spec in a back-compatible manner. As a result of this, I’ll probably create proposal to run the package type registry along the same lines as the IETF’s provisional header repositories.

This is just a bit of fun I had in Java based on some of the ideas we’ve been coming up with on Chem4Word in C#.

The basic idea is to implement “kind-of” duck typing in statically typed languages. That is, you might want to define an interface, see whether object classes already implement it, and if they do, you can pretend they implemented that interface when they were written. It’s a possibly correct, certainly naiive implementation, but it illustrates generic methods and a corner of the reflection API, so it might be instructive to some.


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class DuckType {

public static T cast(final Object obj, Class cl) {
Method[] methods = cl.getMethods();
final Map methodMap = new HashMap(
methods.length);
Class objClass = obj.getClass();
boolean implemented = true;
for (Method m : methods) {
try {
Method targetM = objClass.getMethod(m.getName(), m
.getParameterTypes());
if (targetM.getReturnType().isAssignableFrom(m.getReturnType())) {
methodMap.put(m, targetM);
} else {
implemented = false;
break;
}
} catch (NoSuchMethodException e) {
implemented = false;
break;
}
}
if (implemented) {
return (T) Proxy.newProxyInstance(Thread.currentThread()
.getContextClassLoader(), new Class[] { cl },
new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
Method targetMethod = methodMap.get(method);
return targetMethod.invoke(obj, args);
}
});
} else {
// Alternatively you could throw a ClassCastException earlier and never get here.
return null;
}

}

}