0

I use the Hazelcast library in my project. It's executor service has this method:

void executeOnAllMembers(@Nonnull Runnable command);

This can fail at runtime if it is passed a command that does not implement Serializable.

I want to write a unit test that proves all callers of this method pass Serializable commands. I feel I should be able to do this using the Reflections library, but I can't figure it out.

For example, I can find all methods that invoke the method executeOnAllMembers:

Reflections reflections = new Reflections(new ConfigurationBuilder()
        .setUrls(ClasspathHelper.forPackage("com.my.pet.project"))
        .setScanners(new MemberUsageScanner()));
Method executeOnAllMembers =
        IExecutorService.class.getDeclaredMethod("executeOnAllMembers", Runnable.class);
Collection<Member> allMethodsThatInvokeIExecutorServiceExecuteOnAllMembers = 
        reflections.getMemberUsage(executeOnAllMembers);

but I need the type of the argument (some implementation of Runnable that should also implement Serializable) that those methods pass into executeOnAllMembers.

Is this possible? If not, is there another way I can do it?

whistling_marmot
  • 3,561
  • 3
  • 25
  • 39

2 Answers2

0

Is this possible?

Yes you can use the default reflection api available for Java, by looping into the list of all your implemented interfaces. You get this list by calling the method getInterfaces() from you class type.

Person implementing serialization:

public class Person implements Serializable {

    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Looping into the list of interfaces:

public class Program {

    public static void main(String[] args) {
        Person person = new Person("John Doe");
        Arrays.stream(person.getClass().getInterfaces()).forEach(type -> {
            if(type.getTypeName().equals(Serializable.class.getTypeName())) {
                System.out.println("The type is of type Serializable interface");
            } else {
                System.out.println("The type is not of type Serializable interface");
            }
        });
    }
}
Harry Coder
  • 2,429
  • 2
  • 28
  • 32
0

I don't think this is possible with the Reflections library. Instead, I've added an Aspect to assert that the task is Serializable.

@Aspect
public class IExecutorServiceAspect {

    @Pointcut("target(com.hazelcast.core.IExecutorService)")
    public void iExecutorServiceBeans() { }

    @Pointcut("execution(public * com.hazelcast.core.IExecutorService.*(..))")
    public void publicIExecutorServiceMethods() { }

    @Around("iExecutorServiceBeans() && publicIExecutorServiceMethods()")
    public Object assertTaskIsSafeToPassIntoTheHazelcastGrid(ProceedingJoinPoint pjp) throws Throwable {
        Object[] args = pjp.getArgs();
        if (args.length > 0) {
            // The first arg is either a Runnable or Callable. It should also be Serializable.
            assert args[0] instanceof Serializable : "Task must be Serializable " + args[0].getClass(); 
        }
        return pjp.proceed();
    }
}
whistling_marmot
  • 3,561
  • 3
  • 25
  • 39