Automatisches einfügen einer selbst generierten ID in Klasse mit Annotation

norden

Mitglied
Hallo,

ich habe eine etwas außergewöhnliche Idee:

Ich möchte Klassen mit einer eigenen Annotation (@MyAnnotation) annotieren. Die Objekte dieser Klassen sollen dann bei der Initialisierung automatisch eine von mir generierte ID erhalten, die bei der weiteren Verarbeitung genutzt werden kann.

Ich habe mir bereits AspectJ angesehen und folgendes funktioniert schonmal:

Annotation:
Java:
public @interface MyAnnotation{
}

Beispielobjekt:
Java:
@MyAnnotation
public class Example {
	public Example() {
		System.out.println("Constructor");
	}
}

Aspect:
Java:
public aspect ExampleAspect {
	Long id;
	after() : execution((@MyAnnotation *).new(..)){
		id = IdProvider.getId(); // hier wird die ID vergeben
		System.out.println(id);
	}
}


Hier wird jetzt einfach eine ID nach dem Aufruf des Constructors ausgegeben.. ab jetzt habe ich auch nach langem suchen keine Idee, wie ich weitermachen könnte.. :/

Kann mir vielleicht jmd helfen?
 
Kurzum du möchtest also einfach für jedes erzeugte Objekt eine eigens dafür generierte ID ? ich werd sonst aus deiner Fragestellung nicht so ganz schlau , wenn es überhaupt eine ist ^^
 
Kurzum du möchtest also einfach für jedes erzeugte Objekt eine eigens dafür generierte ID ? ich werd sonst aus deiner Fragestellung nicht so ganz schlau , wenn es überhaupt eine ist ^^

Korrekt 😉

ich habe es jetzt folgendermaßen gelöst:

Java:
@Target(ElementType.TYPE)
public @interface MyAnnotation{
}

Java:
@Aspect
public class MyAspect {

	@Pointcut("execution((@MyAnnotation *).new(..))")
	public void bla() {

	}

	@After("bla()")
	public void after(JoinPoint joinPoint) {
		try {
			joinPoint.getTarget().getClass().getDeclaredField("id")
                                                      .set(joinPoint.getTarget(), VersionProvider.getVersion());
		} catch (IllegalAccessException | NoSuchFieldException e) {
			e.printStackTrace();
		}
	}

}


Java:
@MyAnnotation
public class Example {

	public long id;

	public long getId() {
		return id;
	}

}
 
Zuletzt bearbeitet:
Gibt es einen bestimmten Grund, warum diese Klassen nicht einfach von einer Superklasse erben, die ein Feld "id" hat, das im Konstruktor gesetzt wird!?
 
Ja den gibt es:

Wir schreiben eine Datenbank-API, die mit entities von anderen Benutzern der API umgehen können soll. Dabei sollen die Nutzer so wenig wie möglich von der Anwesenheit unserer API mitbekommen. Es ist im Moment eigentlich schon zu viel, das Attribut id (bzw irgend nen anderer name dafür) in der entity unterbringen zu müssen. Erst recht sollen sie aber nicht eine Klasse extenden müssen. Nur eine Annotation wäre genau richtig.
 
ich habe eine etwas außergewöhnliche Idee:

Ich möchte Klassen mit einer eigenen Annotation (@MyAnnotation) annotieren. Die Objekte dieser Klassen sollen dann bei der Initialisierung automatisch eine von mir generierte ID erhalten, die bei der weiteren Verarbeitung genutzt werden kann.

Moment! Reihe dich bitte ganz ganz hinten in der Schlange ein. Du bist sicherlich nicht in den Top 100 der Leute, die diese Idee hatten.

Es ist im Moment eigentlich schon zu viel, das Attribut id (bzw irgend nen anderer name dafür) in der entity unterbringen zu müssen. Erst recht sollen sie aber nicht eine Klasse extenden müssen. Nur eine Annotation wäre genau richtig.

Funktioniert nicht ohne Einschränkung. Du kannst hashCode, equals oder die Referenz benutzen. Ohne eine Instanzvariable, wird das Objekt nie eindeutig. Zudem kannst du dich von dem Traum einer Annotation verabschieden. Schau dir z.B. JPA an:

JPA Entity Primary Key (@Id, @IdClass, @EmbeddedId)

... es hat schon seinen Grund warum es "@Id long id;" heißt und nicht nur "long id;" (oder irgend ein anderer Name).
 
Zuletzt bearbeitet:
Moment! Reihe dich bitte ganz ganz hinten in der Schlange ein. Du bist sicherlich nicht in den Top 100 der Leute, die diese Idee hatten.

Damit meinte ich auch nur, dass es keine alltägliche Idee ist. Ich wollte mich sicherlich nicht als einen der Top 100 darstellen 😛

Funktioniert nicht ohne Einschränkung. Du kannst hashCode, equals oder die Referenz benutzen. Ohne eine Instanzvariable, wird das Objekt nie eindeutig. Zudem kannst du dich von dem Traum einer Annotation verabschieden. Schau dir z.B. JPA an:

JPA Entity Primary Key (@Id, @IdClass, @EmbeddedId)

... es hat schon seinen Grund warum es "@Id long id;" heißt und nicht nur "long id;" (oder irgend ein anderer Name).

Danke für die Info.
 
Hallo,

ich bin nun auf ein anderes Problem gestoßen. Die lib kann momentan nicht in anderen Projekten verwendet werden, da das weaving nicht durchgeführt wird. Ich stehe leider im Moment etwas auf dem Schlauch, ob es überhaupt so möglich ist, wie ich mir das vorstelle.

Hier meine momentane Lösung:

Darwin-Annotation:
Java:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Darwin {}

Darwin-Version-Annotation:
Java:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DarwinVersion {}

Darwin-Aspect:
Java:
import java.lang.reflect.Field;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public privileged aspect DarwinAspect {

	private final static Logger LOGGER = LoggerFactory.getLogger(DarwinAspect.class);

	after(): execution((@(package der klasse).Darwin *).new(..)) {
		int numberOfDarwinVersionFields = 0;
		LOGGER.debug("Try to add version!");
		try {
			Field darwinVersionField = null;
			for (Field field : thisJoinPoint.getTarget().getClass().getDeclaredFields()) {
				if (field.isAnnotationPresent(DarwinVersion.class)) {
					numberOfDarwinVersionFields++;
					LOGGER.debug("DarwinVersion found on field " + field + "!");
					darwinVersionField = field;
				}
			}
			if (numberOfDarwinVersionFields > 1) {
				LOGGER.error("To many @DarwinVersion annotations in class " + thisJoinPoint.getTarget().getClass() + "!");
			} else if (numberOfDarwinVersionFields == 0) {
				LOGGER.error("No DarwinVersion field found in class " + thisJoinPoint.getTarget().getClass() + "!");
			} else if (darwinVersionField != null) {
				LOGGER.debug("Set DarwinVersion on field " + darwinVersionField + "!");
				darwinVersionField.setAccessible(true);
				darwinVersionField.set(thisJoinPoint.getTarget(), VersionProvider.getVersion(thisJoinPoint.getTarget().getClass()));
			}
		} catch (IllegalAccessException e) {
			LOGGER.error(e.getLocalizedMessage());
		}
	}

}

Example of usage:
Java:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


@Darwin
public class Example {

   @DarwinVersion
   private Long version;

   private final static Logger LOGGER = LoggerFactory.getLogger(Example.class);

   public static void main(String[] args) {

      Example example = new Example();
      System.out.println(example);

      Example example1 = new Example();
      System.out.println(example1);

      Example example2 = new Example();
      System.out.println(example2);

      Example example3 = new Example();
      System.out.println(example3);

   }

   @Override
   public String toString() {
      return "Example{" + "version=" + version + '}';
   }
}

In dem Beispiel funktioniert es genau so wie ich will: Beim instanziieren eines "Example"-Objektes wird Automatisch eine Versionsnummer vergeben und in der variable mit der Annotation "DarwinVersion" abgespeichert.

Leider funktioniert das allerdings nur innerhalb des Projektes. Ich möchte aber, dass Nutzer der Darwin-lib selbst Klassen anlegen und mit den Darwin-Annotationen versehen können. Dazu muss doch eigentlich der aspect zur lauf/comile-zeit in die Klasse "geweavet" werden oder?

Viele Grüße,

Marcel
 
Zuletzt bearbeitet:

Zurück
Oben