Adnotacje i wstrzyknęcia

0

Mam taką koncepcję, żeby stworzyć bibliotekę (niewielką), która pozwalałaby w JavaSE używać czegoś takiego jak wstrzyknięcia za pomocą adnotacji. Coś takiego działa w Spring MVC, JavaEE5 (np. @ejb, @Resource) i Seam (@In, @Out). Jak na tą chwilę wymyśliłem, że za pomocą wzorca factory jestem w stanie utworzyć i obsłużyć poprzez refleksje taki mechanizm, czyli pola klasy oznaczone adnotacją mają nadaną automatycznie wartość. Jednak brakuje mi pomysłu jak zrobić, aby tworząc obiekt konstruktorem operatorem new przypisać wartość oznaczonym adnotacjami polom. Troszkę grzebałem i wynalazłem, że jest procesor adnotacji i że mogą one być typu RUNTIME, ale nie umiem tego poskładać. Będę wdzięczny za podpowiedzi.

0

Nie da się Panie. W Javie nie ma przeciążania operatora new. Co najwyżej możesz zrobić metodę inject(Object). W Javie operator new alokuje pamięć i ustawia wskaźnik this, a potem na tym wskaźniku jest wywoływany konstruktor. Nie bardzo jest jak się wstrzelić pomiędzy to.

Możesz własnego ClassLoadera napisać, który by w locie modyfikował bytecode :)

0
donkey7 napisał(a)

Nie da się Panie.

W moim słowniku nie ma takiego stwierdzenia jak "Nie da się" :-) . Ja wiem, że wymienione przykłady używają kontenera i co za tym idzie łatwiej jest zrobić coś po new. Ale po to są adnotacje dostępne w czasie wykonywania, żeby można było coś zdziałać. To, co chcę zrobić ma dziać się po new. Powstaje instancja, a potem wywołuje się metoda, powiedzmy init. Ale nie w konstruktorze, tylko z innego powodu. Nie wiem dokładnie jak to zrobić i dlatego pytam, ale to co się dogrzebałem, to procesor adnotacji, klasa podawana jako parametr do javac już w czasie kompilacji. Tylko nie wiem co dalej i czy na pewno właśnie tak.

0

Adnotacje RUNTIME sa po to abys w czasie runtime mogl odpytac klase / metode / pole o jego anotacje.
New nie przeciazysz. Mysle ze mozesz pobawic sie jakims javassist czy czyms podobnym i dowalac zaraz na koncu new wywolanie wlasnej metody do wstrzykiwania.

0

New nie przeciążysz, ale przecież masz informacje o klasie. Możesz pobrać informacje o polu uczynić je dostępnym, przypisać wartość i po sprawie:

public class A {

	private Object o;

	Object getO() {
		return o;
	}

	public static void main(String[] args) throws IllegalArgumentException,
			SecurityException, InstantiationException, IllegalAccessException,
			InvocationTargetException, NoSuchMethodException,
			ClassNotFoundException, NoSuchFieldException {

		A a = (A) Class.forName("pl.com.kir.elixir.reporting.A")
				.getDeclaredConstructor().newInstance();
		Object o = Class.forName("java.lang.Object").getConstructor()
				.newInstance();
		System.out.println(a.getO());
		System.out.println(o);

		Field oField = A.class.getDeclaredField("o");
		oField.setAccessible(true);
		oField.set(a, o);
		System.out.println(a.getO());
	}
}

Wartości z adnotacji można pobrać informacje i obrabiać je jak zwykłe dane.

0

Jak wspomniałem mam sposób, żeby zrobić coś podobnego, ale jest to mało eleganckie, bo zamiast akcji po new wywołuję obsługę adnotacji w metodzie getInstance (która używa new). Znalazłem takie coś:
http://www.javabeat.net/articles/14-java-60-features-part-2-pluggable-annotation-proce-1.html

Z tego by wynikało, że działa to mniej więcej tak, jak bym chciał. Problem w tym, że "działa" to za dużo powiedziane. Po pierwsze javac wcale nie jest taki sprytny i muszę mu podać kompletną ścieżkę do pliku*.java, a po drugie nawet jak to zrobię, to i tak nie dostaję takiego efektu jak opisany w przykładzie. Dlatego hętnie przeczytam, że ktoś to wypróbował i mu zadziałało :)

0

A zastanawiales sie nad wykorzystaniem AOP?

0
ws napisał(a)

A zastanawiales sie nad wykorzystaniem AOP?

Bardzo krótko. Nie skorzystam. Poza tym wpadło mi w oko coś jak Swing Framework i Weld, który podobno można wykorzystać w JavaSE. Tylko, że ja chcę mieć szybko coś, co pozwoli mi osiągnąć opisany cel, a nie ogromną dokumentację do przeczytania, żeby napisać prostą aplikację. Dlatego na tą chwilę pozostaję przy zasadniczym pytaniu.

0

No przeciez masz podane 2 wyjścia:

  • statycznie poprzez własny program do bytecode enhancement,
  • dynamicznie poprzez napisane własnej klasy classloadera,

Trzeba użyć jakiejś biblioteki do analizy i generacji bytecodu.

0
donki7 napisał(a)

No przeciez masz podane 2 wyjścia:

  • statycznie poprzez własny program do bytecode enhancement,
  • dynamicznie poprzez napisane własnej klasy classloadera,

Trzeba użyć jakiejś biblioteki do analizy i generacji bytecodu.

Nie rozumiem. A dokładniej: w ogóle nie rozumiem co do mnie piszesz. Czy to się odnosi do tego artykułu z linka który wkleiłem? Możesz napisać dlaczego to nie działa? Ja tam się nie dopatrzyłem żadnych wyjść.

0

Nie odnosi się. Jeśli dobrze zrozumiałem to to co chcesz zrobić to zamienienie "new" na "Injector.inject". Nie da się tego zrobić inaczej niż poprzez analizę i modyfikację bytecodu.

Frameworki dostarczające DI działają tak, że same ładują i injectują pola dla ciebie. Jeśli odpalasz new cośtam zamiast Injector.inject cośtam to pola oznaczone adnotacjami nie są wstrzykiwane - przynajmniej tak jest np w Guice.

Nie znam żadnego frameworka, który by wstrzykiwał pola w obiektach tworzonych zwykłym new'em.

Zrobienie prostej metody Injector.inject nie powinno być specjalnie czasochłonne, ale po co to robić skoro jest Google Guice?

Napisz co dokładnie chcesz osiągnąć.

0

True, wszystko co pisze donkey. Rowniez polecam Guice - male, szybkie, proste.

0

Ostatecznie napisałem sobie klasę z metodą getInstance(Class c), nawet mniej niż 100 linijek. Tworzę sobie tą metodą pierwsze okno aplikacji i reszta mi hula aż miło. Muszę tylko uważać, żeby nie odwoływać się do wstrzykiwanych pól w konstruktorze i metodach wywołanych z konstruktora. Nie jest to dokładnie to, co chciałem osiągnąć, bo nie działa samo, ale na moje potrzeby jest to rozwiązanie wystarczające. Zwłaszcza, że to ma być narzędzie, a nie cel sam w sobie. Dzięki za pomoc i podpowiedzi.

1 użytkowników online, w tym zalogowanych: 0, gości: 1