Sì, questo è possibile. Supponiamo di avere una classe hard-wired, forse andare a prendere qualcosa da un database, e si vuole prendere in giro tramite un aspetto:
package de.scrum_master.aop.app;
public class HardWired {
private int id;
private String name;
public HardWired(int id, String name) {
this.id = id;
this.name = name;
}
public void doSomething() {
System.out.println("Fetching values from database");
}
public int getSomething() {
return 11;
}
@Override
public String toString() {
return "HardWired [id=" + id + ", name=" + name + "]";
}
}
Poi c'è un'applicazione po 'driver utilizzando quella stessa classe (non un'interfaccia) :
package de.scrum_master.aop.app;
public class Application {
public static void main(String[] args) {
HardWired hw = new HardWired(999, "My object");
System.out.println(hw);
hw.doSomething();
System.out.println(hw.getSomething());
}
}
l'uscita è la seguente:
HardWired [id=999, name=My object]
Fetching values from database
11
Ora si definisce la classe finta derivato che dovrebbe sostituire l'originale a scopo di test:
package de.scrum_master.aop.mock;
import de.scrum_master.aop.app.HardWired;
public class HardWiredMock extends HardWired {
public HardWiredMock(int id, String name) {
super(id, name);
}
@Override
public void doSomething() {
System.out.println("Mocking database values");
}
@Override
public int getSomething() {
return 22;
}
@Override
public String toString() {
return "Mocked: " + super.toString();
}
}
E infine si definisce un aspetto con una semplice pointcut e consigli per sostituire il valore originale durante ogni chiamata del costruttore:
package de.scrum_master.aop.aspect;
import de.scrum_master.aop.app.HardWired;
import de.scrum_master.aop.mock.HardWiredMock;
public aspect MockInjector {
HardWired around(int p1, String p2) : call(HardWired.new(int, String)) && args(p1, p2) {
return new HardWiredMock(p1, p2);
}
}
L'uscita come desiderato:
Mocked: HardWired [id=999, name=My object]
Mocking database values
22
Fate quello una volta per classe e costruttore e sta bene. Per generalizzare l'approccio avresti bisogno di proprietà joinpoint e, a seconda di quanto lontano vuoi andare, magari di riflessione, ma questo qui è piuttosto semplice. Godere!
Questa è una risposta molto dettagliata, che sembra essere esattamente quello che sto cercando. Grazie! –
Non così veloce! Ho dimenticato di menzionare che per applicarlo su una libreria di terze parti è necessario inserirlo nel codice della lib, sia da LTW che tessendo le classi binarie e sostituendo la lib con un JAR sostitutivo. Il primo è più dinamico, il secondo è più facile da fare se nessun responsabile della sicurezza e materiale per la firma non ti impedisce di sostituire il JAR originale. ;-) – kriegaex
darò un'occhiata e vedrò cosa funziona meglio. Al momento del test, ho il pieno controllo della JVM di hosting e del suo ambiente. –