Втъкаване в изпълнение на toString() с AspectJ

Опит за вплитане в метод по подразбиране toString() за голям брой DTO, като се използва само вплитане по време на компилиране. Целта е да се върне JSON представяне с помощта на библиотеката Jackson.

Следвах предложенията в тази статия, превърнах я в конфигурация на аспект в стил на анотация и завърши със следния код:

public @Aspect class JsonToStringAspect {
    private interface JsonToString {
        public String toString();
    }

    public static class JsonToStringImpl implements JsonToString {
        public String toString() {
            return SingletonJsonEncoder.toJsonString(this);
        }
    }

    @SuppressWarnings("unused")
    @DeclareParents(value = "com.mycompany.dto..*", defaultImpl = JsonToStringImpl.class)
    private JsonToString implementedInterface;
}

Изпълнението на javap на получените класове показва, че те имплементират интерфейса JsonToString, но никъде няма знак за метода toString().

Ако променя името на метода на нещо, което не се сблъсква с Object.toString() (напр. toString2()), методът наистина се добавя.

Някакви улики как да се преодолее това? Може би @Around съвет относно pointcut, който прихваща изпълнението на java.lang.Object.toString(), само за детски класове под пакет com.mycompany.dto? Или начин да принудите миксина да се случи?


person raulk    schedule 11.01.2013    source източник
comment
Знам, че не е това, което търсите, но като цяло предлагам AOP да бъде запазено за архитектурни проблеми като транзакции, стратегии за повторен опит, оторизация, одит и т.н., а не за по-обикновени неща като едноредов toString() метод. Очевидно това помага да запазите вашите toString() методи СУХИ, но също така е и малко неочевидна магия това прави кодовата база по-сложна.   -  person SingleShot    schedule 13.01.2013
comment
@SingleShot Има голяма разлика между тъкането по време на зареждане и тъкането по време на компилиране. Споделям вашето предложение, ако го поставите в контекста на тъкането по време на натоварване. Но сплитането по време на компилиране (за което става дума в този въпрос) е напълно валиден и разумен начин да запазите кодовата си база СУХА. Освен това не смятам, че твърдението ти изобщо е валидно. Магията е много по-опасна при извършване на операции за промяна на състоянието (напр. съвети за транзакции), отколкото прост метод toString(), който е (или трябва да бъде) само за четене. Така че, следвайки аргумента ви за усложнения, AOP никога не трябва да се използва изобщо.   -  person raulk    schedule 14.01.2013


Отговори (1)


Опитах вашия сценарий и можех да копирам поведението, опитах също комбинации от @DeclareMixin вместо @DeclareParent и също не можах да накарам това да работи. Това, което работи за мен обаче, е да използвам native aspectj по този начин:

public aspect JsonToStringAspect {
    private interface JsonToString {}
    declare parents: com.mycompany.dto.* implements JsonToString;

    public String JsonToString.toString() {
        return "Overridden String through JsonToStringAspect";
    }
}

Предполагам, че това може да не е осъществимо с помощта на @AspectJ и може да е възможно само чрез естествени аспекти.

person Biju Kunjummen    schedule 11.01.2013
comment
Бижу, благодаря. Прав си, работи с оригинална нотация на AspectJ. Можете ли да премахнете метода toString2() от вашия пример, тъй като не е подходящ и може да обърка другите? След това ще маркирам отговора ви като правилен. Благодаря. - person raulk; 13.01.2013