From aeb4cbf5a1566238b7162efbc6dbd5a25a831f3d Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Sat, 11 Oct 2025 10:48:04 +0000 Subject: [PATCH 1/2] add deadline --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 87ffcbb..1a6a1a9 100644 --- a/README.md +++ b/README.md @@ -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** Ваша задача --- написать генератор экземпляров произвольных классов. From 65ef82ffe15c0cd07bb2235993186c672ccc4236 Mon Sep 17 00:00:00 2001 From: Vadim Date: Sun, 19 Oct 2025 20:17:33 +0300 Subject: [PATCH 2/2] =?UTF-8?q?=D0=9B=D0=B0=D0=B1=D0=BE=D1=80=D0=B0=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=BD=D0=B0=D1=8F=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=20=E2=84=962=20-=20=D0=93=D0=B5=D0=BD=D0=B5=D1=80=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 5 +- .../java/org/example/GenerateExample.java | 38 ++++- .../org/example/classes/BinaryTreeNode.java | 12 ++ src/main/java/org/example/classes/Cart.java | 10 ++ .../java/org/example/classes/Example.java | 3 + .../java/org/example/classes/Product.java | 10 +- .../java/org/example/classes/Rectangle.java | 11 ++ src/main/java/org/example/classes/Shape.java | 3 + .../java/org/example/classes/Triangle.java | 12 ++ .../org/example/generator/Generatable.java | 12 ++ .../java/org/example/generator/Generator.java | 116 ++++++++++++- src/test/java/GeneratorTest.java | 157 ++++++++++++++++++ 12 files changed, 372 insertions(+), 17 deletions(-) create mode 100644 src/main/java/org/example/generator/Generatable.java create mode 100644 src/test/java/GeneratorTest.java diff --git a/build.gradle.kts b/build.gradle.kts index b4738ae..b7d2f42 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,8 +11,9 @@ repositories { dependencies { testImplementation(platform("org.junit:junit-bom:5.10.0")) - testImplementation("org.junit.jupiter:junit-jupiter") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") + testImplementation("org.junit.jupiter:junit-jupiter-api") + testImplementation("org.junit.jupiter:junit-jupiter-params") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") } tasks.test { diff --git a/src/main/java/org/example/GenerateExample.java b/src/main/java/org/example/GenerateExample.java index 47679a9..8488948 100644 --- a/src/main/java/org/example/GenerateExample.java +++ b/src/main/java/org/example/GenerateExample.java @@ -1,17 +1,45 @@ package org.example; - -import org.example.classes.Example; +import org.example.classes.*; import org.example.generator.Generator; public class GenerateExample { public static void main(String[] args) { var gen = new Generator(); + try { - Object generated = gen.generateValueOfType(Example.class); - System.out.println(generated); + System.out.println("=== Testing Generator ==="); + + System.out.println("\n1. Generating Example:"); + Object example = gen.generateValueOfType(Example.class); + System.out.println(example); + + System.out.println("\n2. Generating Product:"); + Object product = gen.generateValueOfType(Product.class); + System.out.println(product); + + System.out.println("\n3. Generating Rectangle:"); + Object rectangle = gen.generateValueOfType(Rectangle.class); + System.out.println(rectangle); + + System.out.println("\n4. Generating Triangle:"); + Object triangle = gen.generateValueOfType(Triangle.class); + System.out.println(triangle); + + System.out.println("\n5. Generating BinaryTreeNode:"); + Object node = gen.generateValueOfType(BinaryTreeNode.class); + System.out.println(node); + + System.out.println("\n6. Generating Cart:"); + Object cart = gen.generateValueOfType(Cart.class); + System.out.println(cart); + + System.out.println("\n7. Generating Shape (interface):"); + Object shape = gen.generateValueOfType(Shape.class); + System.out.println(shape); + } catch (Throwable e) { - throw new RuntimeException(e); + e.printStackTrace(); } } } \ No newline at end of file diff --git a/src/main/java/org/example/classes/BinaryTreeNode.java b/src/main/java/org/example/classes/BinaryTreeNode.java index 046ff56..be25504 100644 --- a/src/main/java/org/example/classes/BinaryTreeNode.java +++ b/src/main/java/org/example/classes/BinaryTreeNode.java @@ -1,5 +1,8 @@ package org.example.classes; +import org.example.generator.Generatable; + +@Generatable public class BinaryTreeNode { private Integer data; private BinaryTreeNode left; @@ -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 + + '}'; + } } diff --git a/src/main/java/org/example/classes/Cart.java b/src/main/java/org/example/classes/Cart.java index 965237d..e9698e6 100644 --- a/src/main/java/org/example/classes/Cart.java +++ b/src/main/java/org/example/classes/Cart.java @@ -1,7 +1,10 @@ package org.example.classes; +import org.example.generator.Generatable; + import java.util.List; +@Generatable public class Cart { private List items; @@ -18,4 +21,11 @@ public void setItems(List items) { } // Конструктор, методы добавления и удаления товаров, геттеры и другие методы + + @Override + public String toString() { + return "Cart{" + + "items=" + items + + '}'; + } } \ No newline at end of file diff --git a/src/main/java/org/example/classes/Example.java b/src/main/java/org/example/classes/Example.java index eac9463..e0c8d1c 100644 --- a/src/main/java/org/example/classes/Example.java +++ b/src/main/java/org/example/classes/Example.java @@ -1,5 +1,8 @@ package org.example.classes; +import org.example.generator.Generatable; + +@Generatable public class Example { int i; diff --git a/src/main/java/org/example/classes/Product.java b/src/main/java/org/example/classes/Product.java index e7dcc89..41d10bd 100644 --- a/src/main/java/org/example/classes/Product.java +++ b/src/main/java/org/example/classes/Product.java @@ -1,5 +1,9 @@ package org.example.classes; + +import org.example.generator.Generatable; + +@Generatable public class Product { private String name; private double price; @@ -42,7 +46,9 @@ public boolean equals(Object obj) { @Override public String toString() { - return super.toString(); + return "Product{" + + "name='" + name + '\'' + + ", price=" + price + + '}'; } - } diff --git a/src/main/java/org/example/classes/Rectangle.java b/src/main/java/org/example/classes/Rectangle.java index 90b0886..d4e2320 100644 --- a/src/main/java/org/example/classes/Rectangle.java +++ b/src/main/java/org/example/classes/Rectangle.java @@ -1,5 +1,8 @@ package org.example.classes; +import org.example.generator.Generatable; + +@Generatable public class Rectangle implements Shape { private double length; private double width; @@ -18,4 +21,12 @@ public double getArea() { public double getPerimeter() { return 2 * (length + width); } + + @Override + public String toString() { + return "Rectangle{" + + "length=" + length + + ", width=" + width + + '}'; + } } \ No newline at end of file diff --git a/src/main/java/org/example/classes/Shape.java b/src/main/java/org/example/classes/Shape.java index c20a851..7a6f41f 100644 --- a/src/main/java/org/example/classes/Shape.java +++ b/src/main/java/org/example/classes/Shape.java @@ -1,5 +1,8 @@ package org.example.classes; +import org.example.generator.Generatable; + +@Generatable public interface Shape { double getArea(); double getPerimeter(); diff --git a/src/main/java/org/example/classes/Triangle.java b/src/main/java/org/example/classes/Triangle.java index 011e96f..1f6a5df 100644 --- a/src/main/java/org/example/classes/Triangle.java +++ b/src/main/java/org/example/classes/Triangle.java @@ -1,5 +1,8 @@ package org.example.classes; +import org.example.generator.Generatable; + +@Generatable public class Triangle implements Shape { private double sideA; private double sideB; @@ -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 + + '}'; + } } \ No newline at end of file diff --git a/src/main/java/org/example/generator/Generatable.java b/src/main/java/org/example/generator/Generatable.java new file mode 100644 index 0000000..18010e1 --- /dev/null +++ b/src/main/java/org/example/generator/Generatable.java @@ -0,0 +1,12 @@ +package org.example.generator; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Generatable { + +} diff --git a/src/main/java/org/example/generator/Generator.java b/src/main/java/org/example/generator/Generator.java index 9d86bfb..3fda90a 100644 --- a/src/main/java/org/example/generator/Generator.java +++ b/src/main/java/org/example/generator/Generator.java @@ -1,18 +1,118 @@ package org.example.generator; +import org.example.classes.*; + import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.Random; +import java.util.*; + public class Generator { + private final Random random = new Random(); + private int currentDepth = 0; + private final int maxDepth = 1; + + public Object generateValueOfType(Class clazz) throws Exception { + if (!clazz.isAnnotationPresent(Generatable.class)) { + throw new Exception("Class with name '" + clazz.getSimpleName() + "' does not have annotation @Generatable"); + } + + if (clazz.isInterface()) { + return generateInterfaceImplementation(clazz); + } + + if (clazz == BinaryTreeNode.class) { + currentDepth++; + if (currentDepth > maxDepth) { + currentDepth--; + return null; + } + } + + try { + Constructor[] constructors = clazz.getDeclaredConstructors(); + Constructor constructor = constructors[0]; + + Class[] parameterTypes = constructor.getParameterTypes(); + Object[] parameters = new Object[parameterTypes.length]; + + int i = 0; + for (Class parameterType : parameterTypes) { + Object value = generateValueForField(parameterType); + parameters[i++] = value; + System.out.println("For field " + parameterType.getName() + " was generate random value: " + value); + } + + return constructor.newInstance(parameters); + } finally { + if (clazz == BinaryTreeNode.class) { + currentDepth--; + } + } + } + + private Object generateInterfaceImplementation(Class clazz) throws Exception { + if (clazz == Shape.class) { + if (random.nextBoolean()) { + return generateValueOfType(Rectangle.class); + } else { + return generateValueOfType(Triangle.class); + } + } + + throw new Exception("Unsupported interface: " + clazz.getSimpleName()); + } + + private Object generateBinaryTreeNode() throws Exception { + Integer data = random.nextInt(100); + + BinaryTreeNode left = null; + BinaryTreeNode right = null; + + if (currentDepth <= maxDepth) { + left = (BinaryTreeNode) generateValueOfType(BinaryTreeNode.class); + right = (BinaryTreeNode) generateValueOfType(BinaryTreeNode.class); + } + + return new BinaryTreeNode(data, left, right); + } - public Object generateValueOfType(Class clazz) throws InvocationTargetException, InstantiationException, IllegalAccessException { - Constructor[] constructors = clazz.getDeclaredConstructors(); + private Object generateValueForField(Class clazz) throws Exception { + if (clazz == BinaryTreeNode.class) { + return generateBinaryTreeNode(); + } - int randomConstructorIndex = new Random().nextInt(constructors.length); - Constructor randomConstructor = constructors[randomConstructorIndex]; - return randomConstructor.newInstance(111); + if (clazz == int.class || clazz == Integer.class) { + return random.nextInt(1000); + } else if (clazz == double.class || clazz == Double.class) { + return random.nextDouble() * 1000; + } else if (clazz == String.class) { + return generateString(); + } else if (List.class.isAssignableFrom(clazz)) { + return generateList(); + } + + throw new Exception("Unsupported class type"); + } + + private Object generateList() throws Exception { + List list = new ArrayList<>(); + int size = random.nextInt(3) + 1; + + for (int i = 0; i < size; i++) { + Object product = generateValueOfType(Product.class); + list.add(product); + } + + return list; } + private Object generateString() { + int length = random.nextInt(10) + 1; + char[] characters = new char[length]; + for (int i = 0; i < length; i++) { + characters[i] = (char) ('a' + random.nextInt(26)); + } -} + return new String(characters); + } +} \ No newline at end of file diff --git a/src/test/java/GeneratorTest.java b/src/test/java/GeneratorTest.java new file mode 100644 index 0000000..db295db --- /dev/null +++ b/src/test/java/GeneratorTest.java @@ -0,0 +1,157 @@ + +import org.example.classes.*; +import org.example.generator.Generator; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.DisplayName; + +import java.lang.reflect.Field; + +import static org.junit.jupiter.api.Assertions.*; + +class GeneratorTest { + + private final Generator generator = new Generator(); + + @Test + @DisplayName("Генерация класса Example") + void whenGenerateExample_thenSuccess() throws Exception { + Object result = generator.generateValueOfType(Example.class); + + Example example = (Example) result; + Field i = example.getClass().getDeclaredField("i"); + i.setAccessible(true); + + assertNotNull(result); + assertInstanceOf(Example.class, result); + assertTrue((int) i.get(example) >= 0 && (int) i.get(example) < 1000); + } + + @Test + @DisplayName("Генерация класса Product") + void whenGenerateProduct_thenSuccess() throws Exception { + Object result = generator.generateValueOfType(Product.class); + + Product product = (Product) result; + + assertNotNull(result); + assertInstanceOf(Product.class, result); + assertNotNull(product.getName()); + assertFalse(product.getName().isEmpty()); + assertTrue(product.getPrice() >= 0 && product.getPrice() <= 1000); + } + + @Test + @DisplayName("Генерация класса Rectangle") + void whenGenerateRectangle_thenSuccess() throws Exception { + Object result = generator.generateValueOfType(Rectangle.class); + + + Rectangle rectangle = (Rectangle) result; + double area = rectangle.getArea(); + double perimeter = rectangle.getPerimeter(); + + assertNotNull(result); + assertInstanceOf(Rectangle.class, result); + assertTrue(area >= 0); + assertTrue(perimeter >= 0); + } + + @Test + @DisplayName("Генерация класса Triangle") + void whenGenerateTriangle_thenSuccess() throws Exception { + Object result = generator.generateValueOfType(Triangle.class); + + Triangle triangle = (Triangle) result; + double perimeter = triangle.getPerimeter(); + + assertNotNull(result); + assertInstanceOf(Triangle.class, result); + assertTrue(perimeter >= 0); + } + + @Test + @DisplayName("Генерация BinaryTreeNode с ограниченной глубиной") + void whenGenerateBinaryTreeNode_thenSuccess() throws Exception { + Object result = generator.generateValueOfType(BinaryTreeNode.class); + + assertNotNull(result); + assertInstanceOf(BinaryTreeNode.class, result); + + BinaryTreeNode node = (BinaryTreeNode) result; + assertNotNull(node.getData()); + assertTrue(node.getData() >= 0 && node.getData() < 1000); + + if (node.getLeft() != null) { + assertInstanceOf(BinaryTreeNode.class, node.getLeft()); + assertNull(node.getLeft().getLeft()); + assertNull(node.getLeft().getRight()); + } + + if (node.getRight() != null) { + assertInstanceOf(BinaryTreeNode.class, node.getRight()); + assertNull(node.getRight().getLeft()); + assertNull(node.getRight().getRight()); + } + } + + @Test + @DisplayName("Генерация Cart с List") + void whenGenerateCart_thenSuccess() throws Exception { + Object result = generator.generateValueOfType(Cart.class); + + Cart cart = (Cart) result; + + assertNotNull(result); + assertInstanceOf(Cart.class, result); + assertNotNull(cart.getItems()); + assertFalse(cart.getItems().isEmpty()); + assertTrue(cart.getItems().size() >= 1 && cart.getItems().size() <= 3); + + for (Product product : cart.getItems()) { + assertInstanceOf(Product.class, product); + assertNotNull(product.getName()); + assertTrue(product.getPrice() >= 0); + } + } + + @Test + @DisplayName("Генерация интерфейса Shape") + void whenGenerateShape_thenSuccess() throws Exception { + Object result = generator.generateValueOfType(Shape.class); + + Shape shape = (Shape) result; + double perimeter = shape.getPerimeter(); + + assertNotNull(result); + assertInstanceOf(Shape.class, result); + assertTrue(perimeter >= 0); + assertTrue(shape instanceof Rectangle || shape instanceof Triangle); + } + + @Test + @DisplayName("Тестирование множественной генерации для разнообразия результатов") + void multipleGenerationGivesDifferentResults() throws Exception { + Product product1 = (Product) generator.generateValueOfType(Product.class); + Product product2 = (Product) generator.generateValueOfType(Product.class); + + assertNotEquals(product1.getName(), product2.getName()); + assertNotEquals(product1.getPrice(), product2.getPrice()); + } + + @Test + @DisplayName("Генерация Shape с разными реализациями") + void shapeGeneratesDifferentImplementations() throws Exception { + boolean foundRectangle = false; + boolean foundTriangle = false; + + for (int i = 0; i < 10; i++) { + Shape shape = (Shape) generator.generateValueOfType(Shape.class); + if (shape instanceof Rectangle) foundRectangle = true; + if (shape instanceof Triangle) foundTriangle = true; + if (foundRectangle && foundTriangle) break; + } + + assertTrue(foundRectangle, "Должен генерироваться Rectangle"); + assertTrue(foundTriangle, "Должен генерироваться Triangle"); + } +} \ No newline at end of file