Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/java.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Build Java

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5
- name: Set up JDK 21
uses: actions/setup-java@v5
with:
java-version: '21'
distribution: 'temurin'
- name: Validate Gradle wrapper
uses: gradle/actions/wrapper-validation@v5
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v5
- name: Build with Gradle
run: ./gradlew build
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/4ISSpVK4)
**Java reflection**

Ваша задача --- написать генератор экземпляров произвольных классов.
Expand Down
14 changes: 14 additions & 0 deletions annotation-processor/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
plugins {
id("java")
}

group = "org.example"
version = "1.0-SNAPSHOT"

repositories {
mavenCentral()
}

dependencies {
implementation(project(":core"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package org.example.annotation.processor;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
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.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;

import org.example.annotation.Generatable;

@SupportedSourceVersion(SourceVersion.RELEASE_21)
@SupportedAnnotationTypes("org.example.annotation.Generatable")
public class GeneratableProcessor extends AbstractProcessor {
private boolean hasGenerated = false;

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (hasGenerated || roundEnv.processingOver()) {
return true;
}

var annotatedElements = roundEnv.getElementsAnnotatedWith(Generatable.class);

var typeElements = annotatedElements.stream()
.map(this::getTypeElement)
.filter(Objects::nonNull)
.toList();

if (!typeElements.isEmpty()) {
generateGeneratableRegistry(typeElements);
hasGenerated = true;
}

return true;
}

private TypeElement getTypeElement(Element element) {
return (element.getKind() == ElementKind.CLASS) ? (TypeElement) element : null;
}

/**
* При процессинге аннотации {@link Generatable} "кэшируем" классы, которые её используют,
* для дальнейшего поиска при генерации производных классов, реализующих интерфейсы
*/
private void generateGeneratableRegistry(List<TypeElement> typeElements) {
try {
JavaFileObject file = processingEnv.getFiler()
.createSourceFile("org.example.generator.GeneratableRegistry");

try (Writer writer = new BufferedWriter(file.openWriter())) {
writer.write("package org.example.generator;\n\n");
writer.write("import java.util.List;\n\n");
writer.write("// Auto-generated by GeneratableProcessor. Don't modify this code!\n");
writer.write("public class GeneratableRegistry {\n");
writer.write(" public static List<Class<?>> getAllGeneratableClasses() {\n");
writer.write(" return List.of(\n");

for (int i = 0; i < typeElements.size(); i++) {
writer.write(" " + typeElements.get(i).getQualifiedName().toString() + ".class");
if (i < typeElements.size() - 1) {
writer.write(",\n");
} else {
writer.write("\n");
}
}

writer.write(" );\n");
writer.write(" }\n");
writer.write("}\n");
}

processingEnv.getMessager().printMessage(
Diagnostic.Kind.NOTE,
"Successfully generated GeneratableRegistry with " + typeElements.size() + " classes"
);
} catch (IOException e) {
processingEnv.getMessager().printMessage(
Diagnostic.Kind.ERROR,
"Failed to generate registry: " + e.getMessage()
);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.example.annotation.processor.GeneratableProcessor
3 changes: 3 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ repositories {
}

dependencies {
implementation(project(":core"))
annotationProcessor(project(":annotation-processor"))

testImplementation(platform("org.junit:junit-bom:5.10.0"))
testImplementation("org.junit.jupiter:junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
Expand Down
13 changes: 13 additions & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
plugins {
id("java")
}

group = "org.example"
version = "1.0-SNAPSHOT"

repositories {
mavenCentral()
}

dependencies {
}
13 changes: 13 additions & 0 deletions core/src/main/java/org/example/annotation/Generatable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.example.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Generatable {
}
4 changes: 3 additions & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
rootProject.name = "reflection-template"
rootProject.name = "reflection-template"
include("annotation-processor")
include("core")
9 changes: 8 additions & 1 deletion src/main/java/org/example/GenerateExample.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package org.example;


import java.util.List;
import java.util.Random;

import org.example.classes.Example;
import org.example.generator.Generator;
import org.example.generator.PrimitiveValueGenerator;
import org.example.generator.StringValueGenerator;

public class GenerateExample {
public static void main(String[] args) {
var gen = new Generator();
var random = new Random(42);
var gen = new Generator(random, List.of(new PrimitiveValueGenerator(random), new StringValueGenerator(random)));

try {
Object generated = gen.generateValueOfType(Example.class);
System.out.println(generated);
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/org/example/classes/BinaryTreeNode.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.example.classes;

import org.example.annotation.Generatable;

@Generatable
public class BinaryTreeNode {
private Integer data;
private BinaryTreeNode left;
Expand Down Expand Up @@ -30,4 +33,13 @@ public void setLeft(BinaryTreeNode left) {
public void setRight(BinaryTreeNode right) {
this.right = right;
}

@Override
public String toString() {
return "BinaryTreeNode{" +
"data=" + data +
", left=" + left +
", right=" + right +
'}';
}
}
12 changes: 11 additions & 1 deletion src/main/java/org/example/classes/Cart.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import java.util.List;

import org.example.annotation.Generatable;

@Generatable
public class Cart {
private List<Product> items;

Expand All @@ -18,4 +21,11 @@ public void setItems(List<Product> items) {
}

// Конструктор, методы добавления и удаления товаров, геттеры и другие методы
}

@Override
public String toString() {
return "Cart{" +
"items=" + items +
'}';
}
}
31 changes: 31 additions & 0 deletions src/main/java/org/example/classes/CartStorage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.example.classes;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.example.annotation.Generatable;

@Generatable
public class CartStorage {
private final Map<String, List<Cart>> buyerCarts;

public CartStorage(Map<String, List<Cart>> buyerCarts) {
this.buyerCarts = buyerCarts;
}

public Map<String, List<Cart>> getBuyerCarts() {
return buyerCarts;
}

public void addBuyerCart(String buyer, Cart cart) {
buyerCarts.computeIfAbsent(buyer, k -> new ArrayList<>()).add(cart);
}

@Override
public String toString() {
return "CartStorage{" +
"buyerCarts=" + buyerCarts +
'}';
}
}
7 changes: 6 additions & 1 deletion src/main/java/org/example/classes/Example.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.example.classes;

import org.example.annotation.Generatable;

@Generatable
public class Example {
int i;

Expand All @@ -9,6 +12,8 @@ public Example(int i) {

@Override
public String toString() {
return "Example(" + i + ")";
return "Example{" +
"i=" + i +
'}';
}
}
19 changes: 7 additions & 12 deletions src/main/java/org/example/classes/Product.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.example.classes;

import org.example.annotation.Generatable;

@Generatable
public class Product {
private String name;
private double price;
Expand Down Expand Up @@ -30,19 +33,11 @@ public void setPrice(double price) {
this.price = price;
}

@Override
public int hashCode() {
return super.hashCode();
}

@Override
public boolean equals(Object obj) {
return super.equals(obj);
}

@Override
public String toString() {
return super.toString();
return "Product{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}

}
13 changes: 12 additions & 1 deletion src/main/java/org/example/classes/Rectangle.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.example.classes;

import org.example.annotation.Generatable;

@Generatable
public class Rectangle implements Shape {
private double length;
private double width;
Expand All @@ -18,4 +21,12 @@ public double getArea() {
public double getPerimeter() {
return 2 * (length + width);
}
}

@Override
public String toString() {
return "Rectangle{" +
"length=" + length +
", width=" + width +
'}';
}
}
2 changes: 1 addition & 1 deletion src/main/java/org/example/classes/Shape.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
public interface Shape {
double getArea();
double getPerimeter();
}
}
14 changes: 13 additions & 1 deletion src/main/java/org/example/classes/Triangle.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.example.classes;

import org.example.annotation.Generatable;

@Generatable
public class Triangle implements Shape {
private double sideA;
private double sideB;
Expand All @@ -21,4 +24,13 @@ public double getArea() {
public double getPerimeter() {
return sideA + sideB + sideC;
}
}

@Override
public String toString() {
return "Triangle{" +
"sideA=" + sideA +
", sideB=" + sideB +
", sideC=" + sideC +
'}';
}
}
Loading