Ich habe in einer Java Library (lombok) gesehen, dass mit Annotations Konstruktoren erstellen kann. Das gefällt mir sehr. Jedoch besteht in dieser Bibliothek, nicht die Möglichkeit, mit einer Annotation folgendes zu erzeugen.
Ich habe mir dazu folgendes erstellt.
Ich habe folgende Basisklasse:
Meine Klasse, die BaseEntity erweitert sieht wie folgt aus:
Ich habe außerdem och im Verzeichnis main/ressources/META-INF/services: eine Datei namens: javax.annotation.processing.Processor, die folgendes enthält:
Meine Build.gradle.kts sieht wiefolgt aus:
Wenn ich in der Main Klasse folgendes aufrufe erhalte ich trotz mehrfachem build folgende Fehlermeldung:
Fehlerneldung:
Fehler: Konstruktor ClubType in Klasse ClubType kann nicht auf die angegebenen Typen angewendet werden.
ClubType ct = new ClubType(1);
^
Erforderlich: keine Argumente
Ermittelt: int
Grund: Liste der tatsächlichen Argumente hat eine andere Länge als die der formalen Argumente
Wo ist mein Fehler?
Vielen Dank im Voraus.
Java:
// Constructor for setting id
public ClassName(Integer id) {
super(id);
}
Java:
package org.mjannek.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface GenerateConstructor {
}
package org.mjannek.annotation;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.io.Writer;
import java.util.Set;
@SupportedAnnotationTypes("org.mjannek.annotation.GenerateConstructor")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class GenerateConstructorProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (Element element : roundEnv.getElementsAnnotatedWith(GenerateConstructor.class)) {
if (element.getKind().isClass()) {
TypeElement typeElement = (TypeElement) element;
String className = typeElement.getSimpleName().toString();
String packageName = processingEnv.getElementUtils().getPackageOf(typeElement).toString();
if (!hasConstructor(typeElement)) {
String constructor = String.format("public %s(Integer id) { super(id); }", className);
String source = String.format("package %s;\n\npublic class %s {\n%s\n}", packageName, className, constructor);
try {
JavaFileObject file = processingEnv.getFiler().createSourceFile(packageName + "." + className);
try (Writer writer = file.openWriter()) {
writer.write(source);
}
} catch (IOException e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Error generating constructor: " + e.getMessage());
}
}
}
}
return true;
}
private boolean hasConstructor(TypeElement typeElement) {
return ElementFilter.constructorsIn(typeElement.getEnclosedElements())
.stream()
.anyMatch(constructor -> constructor.getModifiers().contains(Modifier.PUBLIC));
}
}
Ich habe folgende Basisklasse:
Java:
package org.mjannek.database.entity;
import java.io.*;
import java.sql.*;
import java.time.*;
import javax.persistence.*;
import javax.persistence.ForeignKey;
import javax.persistence.Table;
import lombok.*;
import org.hibernate.annotations.*;
import org.mjannek.sport.buli.database.table.*;
@MappedSuperclass
@FilterDef(name = "deletedFilter", parameters = @ParamDef(name = "isDeleted", type = "boolean"))
@Filter(name = "deletedFilter", condition = "deleted = :isDeleted")
@Getter
@Setter
@ToString
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public abstract class BaseEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@EqualsAndHashCode.Include
private Integer id;
@Column(name = "createdat", updatable = false, nullable = false)
private Timestamp createdAt;
@Column(name = "updatedat", nullable = false)
private Timestamp updatedAt;
@Column(name = "deleted")
private Boolean deleted = false;
@ManyToOne
@JoinColumn(name = "createdby", updatable = false, foreignKey = @ForeignKey(name = "fk_baseentity_createdby"))
private User createdBy;
@ManyToOne
@JoinColumn(name = "updatedby", foreignKey = @ForeignKey(name = "fk_baseentity_updatedby"))
private User updatedBy;
@Column(name = "deletedat")
private Timestamp deletedAt;
@ManyToOne
@JoinColumn(name = "deletedby", foreignKey = @ForeignKey(name = "fk_baseentity_deletedby"))
private User deletedBy;
@Version
private Integer version;
// Basis-Konstruktor
public BaseEntity() {
this.deleted = false;
}
public BaseEntity(Integer id) {
this.id = id;
this.deleted = false;
}
@PrePersist
protected void onCreate() {
this.createdAt = Timestamp.valueOf(LocalDateTime.now());
this.updatedAt = Timestamp.valueOf(LocalDateTime.now());
}
@PreUpdate
protected void onUpdate() {
this.updatedAt = Timestamp.valueOf(LocalDateTime.now());
}
// Utility Methods
public void markAsDeleted(User deletedByUser) {
this.deleted = true;
this.deletedAt = Timestamp.valueOf(LocalDateTime.now());
this.deletedBy = deletedByUser;
}
public void restore() {
this.deleted = false;
this.deletedAt = null;
this.deletedBy = null;
this.updatedAt = Timestamp.valueOf(LocalDateTime.now());
}
public String getTableName() {
// Überprüfen, ob die Annotation @Table vorhanden ist
Table tableAnnotation = this.getClass().getAnnotation(Table.class);
if (tableAnnotation != null) {
return tableAnnotation.name(); // Gibt den Tabellennamen zurück
}
return this.getClass().getSimpleName(); // Fallback, falls keine @Table-Annotation vorhanden ist
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BaseEntity that = (BaseEntity) o;
return id != null && id.equals(that.id);
}
@Override
public int hashCode() {
return getClass().hashCode();
}
}
Meine Klasse, die BaseEntity erweitert sieht wie folgt aus:
Java:
package org.mjannek.sport.buli.database.table;
import javax.persistence.*;
import lombok.*;
import org.mjannek.annotation.*;
import org.mjannek.database.entity.*;
@GenerateConstructor
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@Getter
@Setter
@Entity
@Table(name = "clubtypes")
public class ClubType extends BaseEntity {
@Column(name = "name", nullable = false)
private String name;
@Column(name = "description", columnDefinition = "varchar(255) CHARACTER SET utf8mb4")
private String description;
// Constructor for setting id
public ClubType(Integer id) {
super(id);
}
}
Ich habe außerdem och im Verzeichnis main/ressources/META-INF/services: eine Datei namens: javax.annotation.processing.Processor, die folgendes enthält:
Java:
org.mjannek.annotation.GenerateConstructorProcessor
Code:
plugins {
id("java")
id("application")
}
group = "org.mjannek"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
implementation("org.hibernate:hibernate-core:5.+")
implementation("org.reflections:reflections:0.10.2")
implementation("javax.persistence:javax.persistence-api:2.2")
implementation("org.jsoup:jsoup:1.18.3")
implementation("com.sun.mail:javax.mail:1.6.2")
implementation("com.mchange:c3p0:0.9.5.5")
implementation("jakarta.validation:jakarta.validation-api:2.0.2")
implementation("ch.qos.logback:logback-classic:1.4.12")
implementation("mysql:mysql-connector-java:8.+")
implementation("org.projectlombok:lombok:1.18.22")
testImplementation(platform("org.junit:junit-bom:5.10.0"))
testImplementation("org.junit.jupiter:junit-jupiter")
}
tasks.test {
useJUnitPlatform()
}
Wenn ich in der Main Klasse folgendes aufrufe erhalte ich trotz mehrfachem build folgende Fehlermeldung:
Java:
package org.mjannek;
import org.mjannek.sport.buli.database.table.*;
public class Main {
public static void main(String[] args) {
ClubType ct = new ClubType(1);
}
}
Fehlerneldung:
Fehler: Konstruktor ClubType in Klasse ClubType kann nicht auf die angegebenen Typen angewendet werden.
ClubType ct = new ClubType(1);
^
Erforderlich: keine Argumente
Ermittelt: int
Grund: Liste der tatsächlichen Argumente hat eine andere Länge als die der formalen Argumente
Wo ist mein Fehler?
Vielen Dank im Voraus.