CannotCompileException while Instrumenting Java code with using Java Assist, cannot find class - jvm

I'm trying create a generic Java Agent to instrument any Java application's methods.
I've followed this tutorial https://javapapers.com/core-java/java-instrumentation/ and created a java agent.
The java agent is supposed to look for a particular class ( I'm restricting it to one class now since it's not working for me)
Once the class is found, I'm using JavaAssist API to add a local variable to the beginning of each method and capture the current time. In the end of the method I'd like to simply print the time it took for the method to execute. (Pretty much following all the typical examples about Java agent.
I run my test application ( a web server using Vert.x ) with --javaagent flag pointing to the Java agent jar file I created ( the code is down below).
This works just fine for methods that either don't have return value and no parameters or return/take a primitive type.
However when a method is returning or taking a parameter that is an object from a another class (that has not been loaded yet I think) I get a CannotCompileException exception with the message that that class which is in the parameters list or in the return statement is not found.
For example the instrumentation for this method works:
#Override
public void start() throws Exception {
logger.debug("started thread {}", Thread.currentThread().getName());
for (int port : ports) {
HttpServer httpServer = getVertx().createHttpServer(httpServerOptions);
Router router = setupRoutes();
httpServer.requestHandler(router::accept);
logger.info("Listening on port {}", port);
httpServer.listen(port);
}
}
However for this method that returns io.vertx.ext.web.Router:
private Router setupRoutes() {
Router router = Router.router(getVertx());
router.get(STATUS_PATH).handler(this::statusHandler);
router.route().handler(BodyHandler.create());
router.post().handler(this::handleBidRequest);
router.put().handler(this::handleBidRequest);
router.get(SLEEP_CONTROLLER_PATH).handler(this::sleepControllerHandler);
return router;
}
I get an exception and the output of my java agent is :
Instrumenting method rubiconproject.com.WebServerVerticle.setupRoutes()
Could not instrument method setupRoutes error: cannot find io.vertx.ext.web.Router
This the code for my java agent:
import java.lang.instrument.Instrumentation;
import transformers.TimeMeasuringTransformer;
public class TimeCapturerAgent {
public static void premain(String agentArgs, Instrumentation inst) {
System.out.println(TimeCapturerAgent.class.getCanonicalName() + " is loaded...... ");
inst.addTransformer(new TimeMeasuringTransformer());
}}
package transformers;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
public class TimeMeasuringTransformer implements ClassFileTransformer {
public TimeMeasuringTransformer() {
System.out.println("TimeMeasuringTransformer added ");
}
#Override
public byte[] transform(ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
if(className != null && className.contains("WebServerVerticle")) {
System.out.println("Instrumenting class " + className);
return modifyClass(classfileBuffer);
}
return null;
}
private byte[] modifyClass(byte[] originalClassfileBuffer) {
ClassPool classPool = ClassPool.getDefault();
CtClass compiledClass;
try {
compiledClass = classPool.makeClass(new ByteArrayInputStream(originalClassfileBuffer));
System.out.println("Created new compiled Class " + compiledClass.getName());
} catch (IOException e) {
e.printStackTrace();
return null;
}
instrumentMethods(compiledClass);
byte [] newClassByteCode = createNewClassByteArray(compiledClass);
compiledClass.detach();
return newClassByteCode;
}
private byte[] createNewClassByteArray(CtClass compiledClass) {
byte[] newClassByteArray = null;
try {
newClassByteArray = compiledClass.toBytecode();
} catch (IOException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
} finally {
return newClassByteArray;
}
}
private void instrumentMethods(CtClass compiledClass) {
CtMethod[] methods = compiledClass.getDeclaredMethods();
System.out.println("Class has " + methods.length + " methods");
for (CtMethod method : methods) {
try {
System.out.println("Instrumenting method " + method.getLongName());
method.addLocalVariable("startTime", CtClass.longType);
method.insertBefore("startTime = System.nanoTime();");
method.insertAfter("System.out.println(\"Execution Duration "
+ "(nano sec): \"+ (System.nanoTime() - startTime) );");
} catch (CannotCompileException e) {
System.out.println("Could not instrument method " + method.getName()+" error: " + e.getMessage());
continue;
}
}
}}

Related

C3P0, rawConnectionOperation() & java.lang.IllegalArgumentException

I am attempting to use a non-standard method, getServerJobIdentifier(), that is part of the IBM Java Tool Box (jt400.jar) and class com.ibm.as400.access.AS400JDBCConnection with C3P0 & rawConnectionOperation(). I am getting "java.lang.IllegalArgumentException: object is not an instance of declaring class". I have tried numerous options but have not stumbled upon the correct parameters to pass. I am using C3P0 0.9.5.4. Code snippet follows:
// The method I want to call.
// getServerJobIdentifier, public abstract java.lang.String com.ibm.as400.access.AS400JDBCConnection.getServerJobIdentifier()
String driverClassName = "com.ibm.as400.access.AS400JDBCDriver";
String m_DatabaseConnectionString = "jdbc:db2:*local;naming=sql;extended metadata=true";
Connection m_dbConnection;
ComboPooledDataSource m_cpds;
m_cpds = new ComboPooledDataSource();
try {
m_cpds.setDriverClass(driverClassName); //loads the jdbc driver
}
catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
m_cpds.setJdbcUrl(m_DatabaseConnectionString);
m_dbConnection = m_cpds.getConnection();
String qualifiedName = "";
C3P0ProxyConnection castCon = (C3P0ProxyConnection)m_dbConnection;
Method m = AS400JDBCConnection.class.getDeclaredMethod("getServerJobIdentifier");
// This does return what I want. getServerJobIdentified() has no parameters.
System.out.println("method=" + m.toString());
Object[] args = new Object[] {};
System.out.println("calling rawConnectionOperation");
qualifiedName = (String) castCon.rawConnectionOperation(m, C3P0ProxyConnection.RAW_CONNECTION, args);
// never gets here
System.out.println("qualifiedName=" + qualifiedName);
I know I'm that close or I think I am. Thanks!
import java.util.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import com.mchange.v2.c3p0.*;
import com.ibm.as400.access.AS400;
import com.ibm.as400.access.AS400JDBCConnection;
import com.ibm.as400.access.AS400SecurityException;
import com.ibm.db2.jdbc.app.DB2Connection;
// javac -cp :./c3p0-0.9.5.4.jar:./mchange-commons-java-0.2.15.jar:./jt400.jar C3P0Main.java
// /QIBM/ProdData/OS400/jt400/lib/jt400Native.jar
// java -cp :./c3p0-0.9.5.4.jar:./mchange-commons-java-0.2.15.jar:./jt400.jar C3P0Main
// or
// java -cp :./c3p0-0.9.5.4.jar:./mchange-commons-java-0.2.15.jar:/QIBM/ProdData/OS400/jt400/lib/jt400Native.jar C3P0Main
// c3p0.acquireRetryAttempts=0
// c3p0.acquireRetryDelay=5000
// c3p0.breakAfterAcquireFailure=false
// c3p0.maxConnectionAge=10800
// c3p0.maxIdleTime=3600
// c3p0.maxIdleTimeExcessConnections=600
// c3p0.automaticTestTable=c3p0test
// c3p0.idleConnectionTestPeriod=600
// c3p0.testConnectionOnCheckout=true
// java -cp :./c3p0-0.9.5.4.jar:./mchange-commons-java-0.2.15.jar:./jt400.jar -Dc3p0.acquireRetryAttempts=0 -Dc3p0.acquireRetryDelay=5000 -Dc3p0.breakAfterAcquireFailure=false -Dc3p0.maxConnectionAge=10800 -Dc3p0.maxIdleTime=3600 -Dc3p0.maxIdleTimeExcessConnections=600 -Dc3p0.automaticTestTable=c3p0test -Dc3p0.idleConnectionTestPeriod=600 -Dc3p0.testConnectionOnCheckout=true C3P0Main
public class C3P0Main {
private Connection m_dbConnection;
private ComboPooledDataSource m_cpds;
private String driverClassName = "com.ibm.as400.access.AS400JDBCDriver";
//private String m_DatabaseConnectionString = "jdbc:as400:BNADEV;naming=sql;extended metadata=true;user=beak;password=roatan12";
private String m_DatabaseConnectionString = "jdbc:as400:BNADEV;naming=sql;extended metadata=true";
private String m_databaseServerJobID;
public C3P0Main() throws SQLException
{
m_cpds = new ComboPooledDataSource();
try {
m_cpds.setDriverClass(driverClassName); //loads the jdbc driver
}
catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
m_cpds.setJdbcUrl(m_DatabaseConnectionString);
}
public void run(String[] args) throws Exception
{
m_dbConnection = m_cpds.getConnection();
System.out.println("m_dbConnection=" + m_dbConnection.toString());
String qualifiedName = "";
try {
// To use it, first cast the returned Connection to a C3P0ProxyConnection.
// Then call the method rawConnectionOperation, supplying the java.lang.reflect.Method object
// for the non-standard method you wish to call as an argument. The Method you supply will
// be invoked on the target you provide on the second argument (null for static methods),
// and using the arguments you supply in the third argument to that function. For the target,
// and for any of the method arguments, you can supply the special token
// C3P0ProxyConnection.RAW_CONNECTION, which will be replaced with the
// underlying vendor-specific Connection object before the Method is invoked.
//
// C3P0ProxyConnection castCon = (C3P0ProxyConnection) c3p0DataSource.getConnection();
// Method m = CLOB.class.getMethod("createTemporary", new Class[]{Connection.class, boolean.class, int.class});
// Object[] args = new Object[] {C3P0ProxyConnection.RAW_CONNECTION, Boolean.valueOf( true ), new Integer( 10 )};
// CLOB oracleCLOB = (CLOB) castCon.rawConnectionOperation(m, null, args);
// getServerJobIdentifier, public abstract java.lang.String com.ibm.as400.access.AS400JDBCConnection.getServerJobIdentifier()
System.out.println("Is a wrapper for DB2Connection=" + m_dbConnection.isWrapperFor(com.ibm.db2.jdbc.app.DB2Connection.class));
System.out.println("Is a wrapper for AS400JDBCConnection=" + m_dbConnection.isWrapperFor(AS400JDBCConnection.class));
C3P0ProxyConnection castCon = (C3P0ProxyConnection)m_dbConnection;
System.out.println("C3P0ProxyConnection.RAW_CONNECTION=" + C3P0ProxyConnection.RAW_CONNECTION.getClass().getName());
Method method = AS400JDBCConnection.class.getMethod("getServerJobIdentifier");
System.out.println("method=" + method.toString());
Object[] method_args = new Object[] {};
System.out.println("calling rawConnectionOperation");
try {
qualifiedName = (String) castCon.rawConnectionOperation(method, m_dbConnection, method_args);
System.out.println("qualifiedName=" + qualifiedName);
}
catch (IllegalArgumentException | SQLException | InvocationTargetException | IllegalAccessException e) {
System.out.println(e);
System.out.println("oh well #1.");
}
try {
Object[] method_args = new Object[] {};
qualifiedName = (String) castCon.rawConnectionOperation(method, m_dbConnection, method_args);
System.out.println("qualifiedName=" + qualifiedName);
}
catch (IllegalArgumentException | SQLException | InvocationTargetException | IllegalAccessException e) {
System.out.println(e);
System.out.println("oh well #2.");
}
if (castCon instanceof AS400JDBCConnection) {
System.out.println("YES");
qualifiedName = ((AS400JDBCConnection)C3P0ProxyConnection.RAW_CONNECTION).getServerJobIdentifier();
String jobName = qualifiedName.substring(0, 10).trim();
String jobUser = qualifiedName.substring(10, 20).trim();
String jobNumber = qualifiedName.substring(20).trim();
m_databaseServerJobID = jobNumber + '/' + jobUser + '/' + jobName;
System.out.println("SQL Server Job ID: " + m_databaseServerJobID);
}
else {
System.out.println("m_dbConnection is not an instance of DB2Connection.");
}
}
catch (IllegalArgumentException | SQLException | NoSuchMethodException e) {
System.out.println(e);
System.out.println("oh well.");
}
}
public static void main(java.lang.String args[])
{
try {
C3P0Main app = new C3P0Main();
app.run(args);
}
catch (Exception e) {
e.printStackTrace();
}
}
}

pcap4j+winpcap should I run rpcapd.exe manually?

Hi I have downloaded pcap4j and winpcap and all jar (jna, pcap4j-core-1.8.2, slf4j-api-1.7.25, slf4j-simple-1.7.25) dependency manually. Added to the project and all compile well.
BUT:
when I began to sniff packet.getHeader() and packet.getPayload() returns null!
if I run manually rpcapd.exe then it works...
why?
package sniffer;
import java.io.IOException;
import org.pcap4j.core.BpfProgram.BpfCompileMode;
import org.pcap4j.core.NotOpenException;
import org.pcap4j.core.PacketListener;
import org.pcap4j.core.PcapHandle;
import org.pcap4j.core.PcapNativeException;
import org.pcap4j.core.PcapNetworkInterface;
import org.pcap4j.core.PcapNetworkInterface.PromiscuousMode;
import org.pcap4j.packet.Packet;
import org.pcap4j.util.NifSelector;
public class App {
static PcapNetworkInterface getNetworkDevice() {
PcapNetworkInterface device = null;
try {
device = new NifSelector().selectNetworkInterface();
} catch (IOException e) {
e.printStackTrace();
}
return device;
}
public static void main(String[] args) throws PcapNativeException, NotOpenException {
// The code we had before
PcapNetworkInterface device = getNetworkDevice();
System.out.println("You chose: " + device);
// New code below here
if (device == null) {
System.out.println("No device chosen.");
System.exit(1);
}
// Open the device and get a handle
int snapshotLength = 65536; // in bytes
int readTimeout = 50; // in milliseconds
final PcapHandle handle;
handle = device.openLive(snapshotLength, PromiscuousMode.PROMISCUOUS, readTimeout);
String filter = "tcp port 80";
handle.setFilter(filter, BpfCompileMode.OPTIMIZE);
// Create a listener that defines what to do with the received packets
PacketListener listener = new PacketListener() {
#Override
public void gotPacket(Packet packet) {
// Override the default gotPacket() function and process packet
System.out.println(handle.getTimestamp());
System.out.println(packet);
System.out.println(packet.getHeader());///////////////<<<<<<<<<<<------------
}
};
// Tell the handle to loop using the listener we created
try {
int maxPackets = 50;
handle.loop(maxPackets, listener);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Cleanup when complete
handle.close();
}
}
You need to add a packet factory (e.g. pcap4j-packetfactory-static.jar) to your classpath, or Pcap4J creates UnknownPacket instances, getPayload() and getHeader() of which return null, for all packets.

mystified with javax.sound.sampled.Clip NullPointerException

mystified with javax.sound.sampled.Clip NullPointerException
Running on Eclipse on a Mac.
Input wave file exists,
Constructor works fine. Object instance is created.
Just can't access the instance methods, any of them.
Probably a Java 101 issue here, so I apologize in advance, if so?
Or Eclipses 101, for that matter...
public class AudioClipTester {
public static void main(String[] args)
{
// TODO Auto-generated method stub
AudioClipPlayer mooMoo = new AudioClipPlayer("cow.wav");
mooMoo.play();
}
}
/=====
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
/**
* Handles play, pause, and looping of sounds for the game.
* #author Tyler Thomas
*
*/
public class AudioClipPlayer
{
private Clip myClip;
public AudioClipPlayer(String fileName) {
try {
File file = new File(fileName);
if (file.exists()) {
Clip myClip = AudioSystem.getClip();
System.out.println("file "+fileName+" is in root dir");
AudioInputStream ais = AudioSystem.getAudioInputStream(file.toURI().toURL());
myClip.open(ais);
System.out.println("ais "+ais.toString()+" is open");
}
else {
throw new RuntimeException("Sound: file not found: " + fileName);
}
}
catch (MalformedURLException e) {
throw new RuntimeException("Sound: Malformed URL: " + e);
}
catch (UnsupportedAudioFileException e) {
throw new RuntimeException("Sound: Unsupported Audio File: " + e);
}
catch (IOException e) {
throw new RuntimeException("Sound: Input/Output Error: " + e);
}
catch (LineUnavailableException e) {
throw new RuntimeException("Sound: Line Unavailable: " + e);
}
}
public void play(){
System.out.println("clip "+myClip.toString()+" is about to play");
myClip.setFramePosition(0); // Must always rewind!
myClip.loop(0);
myClip.start();
// Thread.sleep(10000);
}
public void loop(){
myClip.loop(Clip.LOOP_CONTINUOUSLY);
}
public void stop(){
myClip.stop();
}
}
That is because in the following line:
Clip myClip = AudioSystem.getClip();
you declare and initialize local variable and the field myClip stays null. Try to replace the above line with
myClip = AudioSystem.getClip();

junit test with Eclipse

Hi i am trying to use junit and it does not work s well.
Here is my code.
package safe;
import java.lang.reflect.*;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import safe.SafetyException;
public class SafetyInspector {
public static boolean isSafe(Class<?> clazz) throws SafetyException{
if (clazz.equals(Object.class)) return true;
if (clazz == null ) {
throw new SafetyException();
}
Field fields[] = clazz.getDeclaredFields();
for(Field f: fields){
f.setAccessible(true);
int mod = f.getModifiers();
if (Modifier.isFinal(mod)){
continue;
}
else if (Modifier.isPrivate(mod)){
Class<?> typeArray[] = new Class<?>[1] ;
typeArray[0] = f.getType();
try {
Method mSet = clazz.getMethod("set" + f.getName().substring(0, 0).toUpperCase() + f.getName().substring(1),typeArray );
int modMet = mSet.getModifiers();
if(!Modifier.isPublic(modMet)) return false;
if(!mSet.getReturnType().equals(void.class)) return false;
}
catch (SecurityException e) {
throw new SafetyException();
}
catch (NoSuchMethodException e) {
return false;
}
try {
Class<?> typeArray2[] = new Class<?>[1] ;
Method mGet = clazz.getMethod("get" + f.getName().substring(0, 0).toUpperCase() + f.getName().substring(1),typeArray2);
int modMet2 = mGet.getModifiers();
if(!Modifier.isPublic(modMet2)) return false;
if(!mGet.getReturnType().equals(f.getType())) return false;
}
catch (SecurityException e) {
throw new SafetyException() ;
}
catch (NoSuchMethodException e) {
return false;
}
}
}
return isSafe(clazz.getSuperclass());
}
public static void sort(List<Class<?>> classes) throws SafetyException{
for (int i = 1; i < classes.size(); i++) {
for (int j = 0; j < classes.size() - i; j++) {
if (compare(classes.get(j), classes.get(j + 1)) > 0) {
swap(classes, j);
}
}
}
}
public static void reset(Object object) throws SafetyException{
Class c = object.getClass();
Field fields[] = c.getDeclaredFields();
for(Field f :fields ){
if (!isSafe(f.getClass()))
{
f.setAccessible(true);
try{
if(!f.getClass().isPrimitive()){
}
else if(f.getClass().equals(boolean.class)){
f.setBoolean(object, false);
}
else{
f.set(object, 0);
}
}
catch(Exception e)
{
throw new SafetyException();
}
}
}
}
private static int compare(Class<?> o1, Class<?> o2) throws SafetyException {
Field[] fields1 = o1.getDeclaredFields();
int count1 = 0;
for (Field f : fields1){
if (isSafe(f.getClass())) count1++;
}
Field[] fields2 = o2.getDeclaredFields();
int count2 = 0;
for (Field f : fields2){
if (isSafe(f.getClass())) count2++;
}
if (count1 == count2)
return o1.getName().compareTo(o2.getName());
else return count1- count2;
}
private static void swap(List<Class<?>> list, int j) {
Class<?> temp = list.get(j);
list.set(j, list.get(j+1));
list.set(j + 1, temp);
}
};
and here is the code junit test that they gave me.
package test;
import static org.junit.Assert.assertEquals;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.junit.Test;
import safe.SafetyException;
import safe.SafetyInspector;
public class SafetyInspectorTest {
#Test
public void testIsSafeEmployee() throws SafetyException {
assertEquals(false, SafetyInspector.isSafe(Employee.class));
}
#Test
public void testResetEmployee() throws SafetyException {
Employee e = new Employee(123,3000);
SafetyInspector.reset(e);
assertEquals(0, e.id);
assertEquals(3000, e.getSalary());
}
#Test
public void testSort() throws SafetyException {
List<Class<?>> sortedClasses = new LinkedList<Class<?>>();
sortedClasses.add(Employee.class);
List<Class<?>> classes = new LinkedList<Class<?>>(sortedClasses);
Collections.shuffle(classes);
SafetyInspector.sort(classes);
assertEquals(sortedClasses, classes);
}
}
and when I run the safetyInspectorTest as a junitTESTCLASS i get an initialization error. I work with eclipse if it helps and I put Junit as a library of the project.
An initialization error in JUnit is generally caused by a bad classpath. See this related question which also suffered from initialization error:
Eclipse JUnit - possible causes of seeing "initializationError" in Eclipse window
The most likely cause is as that question addressed, you are using a version of JUnit 4 which requires the hamcrest jar to be added. Instead of adding the junit and hamcrest jars you should be able to add the JUnit 4 library on your project's Java Build Path.
Your imports largely look benign but you should confirm safe.SafetyException is on your classpath.
Finally, the initialization error could be caused by a static initialization failure in code that loads before your test runs. The code you've posted looks safe but SafetyException class could possibly have an initialization block to check.

How do I force a method in Groovy to throw an exception

I wanted to write a test for a method in Groovy that throws an IOException. The only way for me to simulate this in the test is to force the method to throw this exception
This is what the original code looks like:
public void cleanUpBermudaFiles(RequestMessage requestMessage)
{
final File sourceDirectory = new File(preferenceService.getPreference("bermuda.landingstrip") + File.separator + requestMessage.getWorkflowId().getValue());
if(sourceDirectory!=null && sourceDirectory.exists())
{
deleteDirectory(sourceDirectory);
}
else
{
LOG.error("Directory must exist in order to delete");
}
}
private void deleteDirectory(File directoryToDelete)
{
try {
FileUtils.deleteDirectory(directoryToDelete);
} catch (Exception e) {
LOG.error("Failed to delete Bermuda files directory located at:" + directoryToDelete.getPath() + "with an exception" + e.getMessage());
}
}
MY TEST: (I'm looking for a way to make deleteDirectory throw IOException)
public void testCleanUpBermudaFailure()
{
workflowId = new WorkflowId("123456")
workflowDirectory = new File(srcDirectory, workflowId.value)
workflowDirectory.mkdir()
File.createTempFile('foo','.lst', workflowDirectory)
def exception = {throw new IOException()}
expect(mockRequestMessage.getWorkflowId()).andReturn(workflowId)
expect(mockPreferenceService.getPreference("bermuda.landingstrip")).andReturn(srcDirectory.path)
replay(mockPreferenceService, mockRequestMessage)
fileCleanUpService.preferenceService = mockPreferenceService
fileCleanUpService.metaClass.deleteDirectory = exception
fileCleanUpService.cleanUpBermudaFiles(mockRequestMessage)
verify(mockPreferenceService, mockRequestMessage)
assert srcDirectory.listFiles().length == 0, 'CleanUp failed'
}
If the service class is a Groovy class, you would want to mock FileUtils like:
FileUtils.metaClass.static.deleteDirectory = { File f -> throw new IOException() }
However, as ataylor pointed out, you cannot intercept calls if it's a Java class. You can find a nice blog post about it here.
You are mocking a no-arg call to deleteDirectory, but the real deleteDirectory takes one argument of type File. Try this:
def exception = { File directoryToDelete -> throw new IOException() }
...
fileCleanUpService.metaClass.deleteDirectory = exception