From 1bbfee3197e3280e012cb03e605d0d1e8d425283 Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Sun, 19 Oct 2025 10:08:52 +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 c3c849aad29e1323c5acedf3916433f268e5de1c Mon Sep 17 00:00:00 2001 From: Vladislav Bandurin Date: Thu, 4 Dec 2025 19:08:47 +0300 Subject: [PATCH 2/2] add lab2 --- .../java/org/example/GenerateExample.java | 61 ++++++- .../org/example/classes/BinaryTreeNode.java | 12 ++ src/main/java/org/example/classes/Cart.java | 11 ++ .../java/org/example/classes/Example.java | 3 + .../java/org/example/classes/Product.java | 16 +- .../java/org/example/classes/Rectangle.java | 13 ++ src/main/java/org/example/classes/Shape.java | 3 + .../java/org/example/classes/Triangle.java | 14 ++ .../org/example/generator/Generatable.java | 11 ++ .../java/org/example/generator/Generator.java | 159 +++++++++++++++++- 10 files changed, 290 insertions(+), 13 deletions(-) create mode 100644 src/main/java/org/example/generator/Generatable.java diff --git a/src/main/java/org/example/GenerateExample.java b/src/main/java/org/example/GenerateExample.java index 47679a9..6722250 100644 --- a/src/main/java/org/example/GenerateExample.java +++ b/src/main/java/org/example/GenerateExample.java @@ -1,17 +1,66 @@ 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(); + Generator gen = new Generator(); + + try { - Object generated = gen.generateValueOfType(Example.class); - System.out.println(generated); + System.out.println("1. Testing Cart generation:"); + Cart cart = (Cart) gen.generateValueOfType(Cart.class); + System.out.println(cart); + System.out.println(); + + System.out.println("2. Testing Product generation:"); + Product product = (Product) gen.generateValueOfType(Product.class); + System.out.println(product); + System.out.println(); + + System.out.println("3. Testing BinaryTreeNode generation:"); + BinaryTreeNode treeNode = (BinaryTreeNode) gen.generateValueOfType(BinaryTreeNode.class); + System.out.println(treeNode); + System.out.println(); + + System.out.println("4. Testing Example generation:"); + Example example = (Example) gen.generateValueOfType(Example.class); + System.out.println(example); + System.out.println(); + + System.out.println("5. Testing Rectangle generation:"); + Rectangle rectangle = (Rectangle) gen.generateValueOfType(Rectangle.class); + System.out.println(rectangle); + System.out.println(); + + System.out.println("6. Testing Triangle generation:"); + Triangle triangle = (Triangle) gen.generateValueOfType(Triangle.class); + System.out.println(triangle); + System.out.println(); + + System.out.println("7. Testing Shape generation (should pick implementation):"); + Shape shape = (Shape) gen.generateValueOfType(Shape.class); + System.out.println(shape.getClass().getSimpleName() + ": " + shape); + System.out.println(); + + System.out.println("8. Generating multiple instances of each type:"); + + System.out.println("\nMultiple Products:"); + for (int i = 0; i < 3; i++) { + Product p = (Product) gen.generateValueOfType(Product.class); + System.out.println(" " + p); + } + + System.out.println("\nMultiple Examples:"); + for (int i = 0; i < 3; i++) { + Example e = (Example) gen.generateValueOfType(Example.class); + System.out.println(" " + e); + } + } catch (Throwable e) { - throw new RuntimeException(e); + System.err.println("Error during generation: " + e.getMessage()); + 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..bff76b2 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 != null ? "TreeNode(" + left.data + ")" : "null") + + ", right=" + (right != null ? "TreeNode(" + right.data + ")" : "null") + + '}'; + } } diff --git a/src/main/java/org/example/classes/Cart.java b/src/main/java/org/example/classes/Cart.java index 965237d..53824f1 100644 --- a/src/main/java/org/example/classes/Cart.java +++ b/src/main/java/org/example/classes/Cart.java @@ -2,6 +2,9 @@ import java.util.List; +import org.example.generator.Generatable; + +@Generatable public class Cart { private List items; @@ -18,4 +21,12 @@ public void setItems(List items) { } // Конструктор, методы добавления и удаления товаров, геттеры и другие методы + + @Override + public String toString() { + return "Cart{" + + "itemsCount=" + (items != null ? items.size() : 0) + + ", 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..fc90e41 100644 --- a/src/main/java/org/example/classes/Product.java +++ b/src/main/java/org/example/classes/Product.java @@ -1,5 +1,8 @@ package org.example.classes; +import org.example.generator.Generatable; + +@Generatable public class Product { private String name; private double price; @@ -30,6 +33,14 @@ public void setPrice(double price) { this.price = price; } + @Override + public String toString() { + return "Product{" + + "name='" + name + '\'' + + ", price=" + String.format("%.2f", price) + + '}'; + } + @Override public int hashCode() { return super.hashCode(); @@ -40,9 +51,4 @@ public boolean equals(Object obj) { return super.equals(obj); } - @Override - public String toString() { - return super.toString(); - } - } diff --git a/src/main/java/org/example/classes/Rectangle.java b/src/main/java/org/example/classes/Rectangle.java index 90b0886..558f927 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,14 @@ public double getArea() { public double getPerimeter() { return 2 * (length + width); } + + @Override + public String toString() { + return "Rectangle{" + + "length=" + String.format("%.2f", length) + + ", width=" + String.format("%.2f", width) + + ", area=" + String.format("%.2f", getArea()) + + ", perimeter=" + String.format("%.2f", getPerimeter()) + + '}'; + } } \ 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..30a267a 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,15 @@ public double getArea() { public double getPerimeter() { return sideA + sideB + sideC; } + + @Override + public String toString() { + return "Triangle{" + + "sides=[" + String.format("%.2f", sideA) + + ", " + String.format("%.2f", sideB) + + ", " + String.format("%.2f", sideC) + "]" + + ", area=" + String.format("%.2f", getArea()) + + ", perimeter=" + String.format("%.2f", getPerimeter()) + + '}'; + } } \ 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..4cd7adc --- /dev/null +++ b/src/main/java/org/example/generator/Generatable.java @@ -0,0 +1,11 @@ +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..a714220 100644 --- a/src/main/java/org/example/generator/Generator.java +++ b/src/main/java/org/example/generator/Generator.java @@ -1,18 +1,173 @@ package org.example.generator; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Parameter; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.Random; +import java.util.function.Supplier; +import java.util.stream.Collectors; public class Generator { + private static final String GENERATABLE_CLASSES_PACKAGE = "org.example.classes"; + private static final Integer MAX_DEPTH = 3; + private static final Integer COLLECTION_OBJECT_COUNT = 5; + private static final Random random = new Random(); + private static final Map, Supplier> BASIC_TYPE_FUNCTIONS; + + static { + Map, Supplier> map = new HashMap<>(); + map.put(byte.class, () -> (byte) random.nextInt(256)); + map.put(Byte.class, () -> (byte) random.nextInt(256)); + map.put(short.class, () -> (short) random.nextInt(65536)); + map.put(Short.class, () -> (short) random.nextInt(65536)); + map.put(int.class, random::nextInt); + map.put(Integer.class, random::nextInt); + map.put(long.class, random::nextLong); + map.put(Long.class, random::nextLong); + map.put(float.class, random::nextFloat); + map.put(Float.class, random::nextFloat); + map.put(double.class, random::nextDouble); + map.put(Double.class, random::nextDouble); + map.put(boolean.class, random::nextBoolean); + map.put(Boolean.class, random::nextBoolean); + map.put(String.class, () -> "str_" + random.nextInt()); + + BASIC_TYPE_FUNCTIONS = Collections.unmodifiableMap(map); + } public Object generateValueOfType(Class clazz) throws InvocationTargetException, InstantiationException, IllegalAccessException { + return generateValueOfTypeInternal(clazz, 0); + } + + private Object generateValueOfTypeInternal(Class clazz, int depth) throws InvocationTargetException, InstantiationException, IllegalAccessException { + if (clazz == null) { + throw new IllegalAccessException("Unable to generate instance for null class"); + } + + if (!clazz.isAnnotationPresent(Generatable.class)) { + throw new IllegalAccessException("Unable to generate instance for non generatable class"); + } + + if (depth == MAX_DEPTH) { + return null; + } + + if (clazz.isInterface()) { + Class implementation = findImplementation(clazz); + return generateValueOfTypeInternal(implementation, depth); + } Constructor[] constructors = clazz.getDeclaredConstructors(); int randomConstructorIndex = new Random().nextInt(constructors.length); - Constructor randomConstructor = constructors[randomConstructorIndex]; - return randomConstructor.newInstance(111); + Constructor constructor = constructors[randomConstructorIndex]; + + Parameter[] parameters = constructor.getParameters(); + if (parameters.length == 0) { + return constructor.newInstance(); + } + + Object[] initializedParams = new Object[parameters.length]; + for (int i = 0; i < parameters.length; i++) { + Parameter parameter = parameters[i]; + initializedParams[i] = generateConstructorValue(parameter, depth + 1); + } + return constructor.newInstance(initializedParams); + } + + private Object generateConstructorValue(Parameter parameter, int depth) throws InvocationTargetException, InstantiationException, IllegalAccessException { + Class parameterType = parameter.getType(); + if (BASIC_TYPE_FUNCTIONS.containsKey(parameterType)) { + return generatePrimitiveOrStringValue(parameterType); + } + if (Collection.class.isAssignableFrom(parameterType)) { + return generateCollection(parameterType, parameter.getParameterizedType(), depth); + } + return generateValueOfTypeInternal(parameterType, depth); } + private Collection generateCollection(Class parameterType, Type genericType, int depth) throws InvocationTargetException, InstantiationException, IllegalAccessException { + Collection result; + if (List.class.isAssignableFrom(parameterType)) { + result = new ArrayList<>(); + } else { + throw new RuntimeException("Collection type " + parameterType + "is not supported"); + } + fillCollection(result, genericType, depth); + return result; + } + + private void fillCollection(Collection result, Type genericType, int depth) throws InvocationTargetException, InstantiationException, IllegalAccessException { + if (!(genericType instanceof ParameterizedType)) { + return; + } + ParameterizedType pType = (ParameterizedType) genericType; + Type[] actualTypeArguments = pType.getActualTypeArguments(); + if (actualTypeArguments.length != 1) { + return; + } + Type typeArgument = actualTypeArguments[0]; + if (typeArgument instanceof Class cl) { + for (int i = 0; i < COLLECTION_OBJECT_COUNT; i++) { + result.add(generateValueOfTypeInternal(cl, depth + 1)); + } + } + } + + private Object generatePrimitiveOrStringValue(Class parameterType) { + Supplier valueGenerator = BASIC_TYPE_FUNCTIONS.get(parameterType); + if (valueGenerator == null) { + throw new IllegalArgumentException("Unexpected parameter type, cannot generate primitive value for " + parameterType.toString()); + } + return valueGenerator.get(); + } + + private Class findImplementation(Class clazz) { + List> allClassesUsingClassLoader = findAllClassesUsingClassLoader(GENERATABLE_CLASSES_PACKAGE); + List implementations = allClassesUsingClassLoader.stream() + .filter(cl -> cl.isAnnotationPresent(Generatable.class)) + .filter(cl -> !cl.isInterface()) + .filter(clazz::isAssignableFrom) + .collect(Collectors.toList()); + if (implementations.isEmpty()) { + throw new RuntimeException("Implementation not found for class " + clazz.getSimpleName()); + } + return implementations.get(random.nextInt(implementations.size())); + } + + public List> findAllClassesUsingClassLoader(String packageName) { + InputStream stream = ClassLoader.getSystemClassLoader() + .getResourceAsStream(packageName.replaceAll("[.]", "/")); + if (stream == null) { + throw new RuntimeException("Unable to get classloader resources from package " + GENERATABLE_CLASSES_PACKAGE); + } + BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); + return reader.lines() + .filter(line -> line.endsWith(".class")) + .map(line -> getClass(line, packageName)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + private Class getClass(String className, String packageName) { + try { + return Class.forName(packageName + "." + + className.substring(0, className.lastIndexOf('.'))); + } catch (ClassNotFoundException e) { + System.err.println("Unable to find class to load: " + className); + } + return null; + } }