cglib Proxy erstellen

sebastianb

Erfahrenes Mitglied
Hallo zusammen,

nach langer Suche habe ich nun endlich mit Hilfe eines Beitrages von Thomas eine Lösung für mein Problem gefunden:
Variablen auf Änderungen hin überwachen?

Ein kleines Problem, dass sich mir nun noch stellt ist, dass in der Zeile 40:

Code:
SomeObject someObject = (SomeObject) enhancer.create(new Class[] { String.class, String.class }, new Object[] { "Hallo", "Welt!" });

ein komplett neues Objekt erstellt wird. Ich hingegen fände es schön, wenn ich der create-Methode ein bestehendes bzw. "gefülltes" Objekt übergeben könnte.
Kennt jemand von Euch hierfür einen eleganten Lösungsweg?

Besten Dank! :)

Sebastian
 
Hallo,

suchst du sowas?
Java:
package de.tutorials.training;

import java.beans.Introspector;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * @author tom
 */
public class ObjectChangeMonitorExample {

  /**
   * @param args
   */
  public static void main(String[] args) {

    SomeObject so = new SomeObject("value1", "value2");

    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(SomeObject.class);
    enhancer.setCallback(new MethodInterceptor() {
      
      private final static String msg = "%s is about to be changed! current value-> %s new value -> %s";
      
      public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        String methodName = method.getName();
        if (methodName.startsWith("set") && method.isAnnotationPresent(TrackChanges.class)) {
            String propertyName = methodName.substring(3);
            String getter = "get"+propertyName;
            String attributeName = Introspector.decapitalize(propertyName);
            Object currentValue = target.getClass().getMethod(getter).invoke(target);
            Object newValue = args[0];
            System.out.printf(msg,attributeName, currentValue,newValue).println();
        }
        return proxy.invokeSuper(target, args);
      }
    });

    SomeObject someObject = (SomeObject) enhancer.create(new Class[]{SomeObject.class}, new Object[]{so});

    System.out.println(someObject);

    someObject.setValue1("foo");
    someObject.setValue2("bar");

    System.out.println(someObject);

  }

  @Retention(RetentionPolicy.RUNTIME)
  @Target(ElementType.METHOD)
  static @interface TrackChanges {}

  static class SomeObject {
    private String value1;

    private String value2;


    public SomeObject() {
      this(null, null);
    }


    public SomeObject(SomeObject that) {
      this(that.value1, that.value2);
    }


    public SomeObject(String value1, String value2) {
      this.value1 = value1;
      this.value2 = value2;
    }


    public String getValue2() {
      return value2;
    }


    @TrackChanges
    public void setValue2(String value2) {
      this.value2 = value2;
    }


    public String getValue1() {
      return value1;
    }


    @TrackChanges
    public void setValue1(String value1) {
      this.value1 = value1;
    }


    @Override
    public String toString() {
      return String.format("SomeObject [value1=%s, value2=%s]", value1, value2);
    }  
  }
}

Gruß Tom
 
Hi Thomas,

vielen Dank für die Anwort. Eigentlich ist das genau wonach ich gesucht habe aber ich habe die Befürchtung, dass das alles ziemlich auf die Performance gehen könnte.
Das eigentlich Ziel ist es jedenfalls mich recht transparent "zwischen" einen Methodenaufruf zu hängen um ggf. ein paar Änderungen vorzunehmen. Aktuell bin ich jedoch gerade am testen, ob nicht AspectJ der bessere Lösungsansatz ist.

Viele Grüße und Besten Dank!

Sebastian
 
Zurück