Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
fc57525
add deadline
github-classroom[bot] Oct 1, 2025
d52b243
первый набросок генератора
deadlovelll Oct 13, 2025
f97fd21
добавил обработку цилических стурктур
deadlovelll Oct 14, 2025
1e865bd
обработка листов
deadlovelll Oct 14, 2025
99940a2
fixed output
deadlovelll Oct 15, 2025
901bcf2
refactor, make code prettier
deadlovelll Oct 15, 2025
0faf9ba
removed unused classes
deadlovelll Oct 15, 2025
7a1863d
moved sequncegenerato
deadlovelll Oct 15, 2025
a522968
сделал код покрасивее
deadlovelll Oct 17, 2025
4c09579
директория с тестами
deadlovelll Oct 17, 2025
6574c7c
тесты для генератора атомиков и генератора мап
deadlovelll Oct 17, 2025
56927be
тест обычных типов
deadlovelll Oct 17, 2025
ccf67ac
тесты для последовательностей
deadlovelll Oct 17, 2025
9759ab9
поправил генератор очередей, тесты на него
deadlovelll Oct 17, 2025
96fa855
добавил тесты с генератором рандомных обьектов
deadlovelll Oct 20, 2025
75c7c46
добавил аннотацию
deadlovelll Oct 20, 2025
8c75d19
ограничил генерацию обьектов аннотацией
deadlovelll Nov 8, 2025
2ac97b9
добавил лимит рекурси
deadlovelll Nov 8, 2025
ef3cd83
добавил проверку isAssignableFrom
deadlovelll Nov 8, 2025
192cbaa
добавил генерацию классов на основе интерфейса
deadlovelll Nov 8, 2025
bec05e5
добавил генерацию дженерик тайпа
deadlovelll Nov 9, 2025
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
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
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
plugins {
id("java")
id("net.bytebuddy.byte-buddy-gradle-plugin") version "1.17.8"
}

group = "org.example"
Expand All @@ -12,6 +13,7 @@ repositories {
dependencies {
testImplementation(platform("org.junit:junit-bom:5.10.0"))
testImplementation("org.junit.jupiter:junit-jupiter")
implementation("net.bytebuddy:byte-buddy:1.15.9")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

Expand Down
21 changes: 17 additions & 4 deletions src/main/java/org/example/GenerateExample.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
package org.example;


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

import java.lang.reflect.Field;

public class GenerateExample {
public static void main(String[] args) {
var gen = new Generator();
try {
Object generated = gen.generateValueOfType(Example.class);
System.out.println(generated);
int depth = 0;
Object generated = gen.generateValueOfType(org.example.classes.Cart.class, depth);
if (generated == null) {
System.out.println("Generated object is null");
return;
}
System.out.println("Generated " + generated);
System.out.println("With attributes:");
Field[] fields = generated.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
System.out.println(
"Field " + field.getName() + " with type:" + field.getType() + " and value:" + field.get(generated)
);
}
} catch (Throwable e) {
throw new RuntimeException(e);
}
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/org/example/annotation/Generatable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.example.annotation;

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 {
}
4 changes: 4 additions & 0 deletions src/main/java/org/example/classes/BinaryTreeNode.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package org.example.classes;


import org.example.annotation.Generatable;

@Generatable
public class BinaryTreeNode {
private Integer data;
private BinaryTreeNode left;
Expand Down
13 changes: 7 additions & 6 deletions src/main/java/org/example/classes/Cart.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
package org.example.classes;

import org.example.annotation.Generatable;

import java.util.List;

@Generatable
public class Cart {
private List<Product> items;
private List<org.example.classes.Product> items;

public Cart(List<Product> items) {
public Cart(List<org.example.classes.Product> items) {
this.items = items;
}

public List<Product> getItems() {
public List<org.example.classes.Product> getItems() {
return items;
}

public void setItems(List<Product> items) {
public void setItems(List<org.example.classes.Product> items) {
this.items = items;
}

// Конструктор, методы добавления и удаления товаров, геттеры и другие методы
}
3 changes: 3 additions & 0 deletions 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 Down
3 changes: 3 additions & 0 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
3 changes: 3 additions & 0 deletions 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 Down
3 changes: 3 additions & 0 deletions 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 Down
34 changes: 34 additions & 0 deletions src/main/java/org/example/generator/AtomicGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package main.java.org.example.generator;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;

public class AtomicGenerator {
private final Random random = new Random();
private final Map<Class<?>, Supplier<Object>> generators;

public AtomicGenerator()
{
generators = new HashMap<>();
generators.put(AtomicInteger.class, () -> new AtomicInteger(random.nextInt(Integer.MAX_VALUE)));
generators.put(AtomicLong.class, () -> new AtomicLong(random.nextInt(Integer.MAX_VALUE)));
generators.put(AtomicBoolean.class, () -> new AtomicBoolean(random.nextBoolean()));
generators.put(AtomicReference.class, () -> new AtomicReference<>(random.nextInt()));
}

public Object generate(Class<?> clazz)
{
Supplier<Object> supplier = generators.get(clazz);
if (supplier == null) {
return null;
}
return supplier.get();
}
}
29 changes: 29 additions & 0 deletions src/main/java/org/example/generator/FromInterfaceGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.example.generator;

import net.bytebuddy.ByteBuddy;

import java.lang.reflect.InvocationTargetException;

public class FromInterfaceGenerator {

public Object generate(Class<?> clazz) throws
ClassNotFoundException,
InvocationTargetException,
IllegalAccessException,
NoSuchMethodException,
InstantiationException
{
String className = clazz.getName();
Class<?> interfaceClass = Class.forName(className);
Class<?> dynamicType = new ByteBuddy()
.subclass(Object.class)
.implement(interfaceClass)
.make()
.load(clazz.getClassLoader())
.getLoaded();
Object instance = dynamicType.getDeclaredConstructor().newInstance();
boolean implementsInterface = clazz.isAssignableFrom(instance.getClass());
System.out.println("Implements interface? " + implementsInterface);
return instance;
}
}
103 changes: 95 additions & 8 deletions src/main/java/org/example/generator/Generator.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,105 @@
package org.example.generator;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Random;
import main.java.org.example.generator.*;
import org.example.annotation.Generatable;

import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.*;


public class Generator {

public Object generateValueOfType(Class<?> clazz) throws InvocationTargetException, InstantiationException, IllegalAccessException {
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
private final Random random = new Random();
private final PrimitiveGenerator primitiveGenerator = new PrimitiveGenerator();
private final AtomicGenerator atomicGenerator = new AtomicGenerator();
private final QueueGenerator queueGenerator = new QueueGenerator();
private final SequenceGenerator sequenceGenerator = new SequenceGenerator();
private final MapGenerator mapGenerator = new MapGenerator();
private final FromInterfaceGenerator fromInterfaceGenerator = new FromInterfaceGenerator();
private static final int MAX_DEPTH = 10;

public Object generateValueOfType(Type type, int depth) throws
InvocationTargetException,
InstantiationException,
IllegalAccessException,
NoSuchMethodException,
ClassNotFoundException
{
if (depth > MAX_DEPTH) {
return null;
}
if (type instanceof Class<?> clazz) {
Object primitiveValue = primitiveGenerator.generate(clazz);
if (primitiveValue != null) return primitiveValue;

Object atomicValue = atomicGenerator.generate(clazz);
if (atomicValue != null) return atomicValue;

Object queueValue = queueGenerator.generate(clazz);
if (queueValue != null) return queueValue;

int randomConstructorIndex = new Random().nextInt(constructors.length);
Constructor<?> randomConstructor = constructors[randomConstructorIndex];
return randomConstructor.newInstance(111);
if (Collection.class.isAssignableFrom(clazz)) {
return sequenceGenerator.generate(clazz);
}
if (Map.class.isAssignableFrom(clazz)) {
return mapGenerator.generate(clazz);
}
if (clazz.isEnum()) {
Object[] arr = clazz.getEnumConstants();
return arr[random.nextInt(arr.length)];
}
if (clazz.isInterface()) {
return fromInterfaceGenerator.generate(clazz);
}
return generateType(clazz, depth + 1);
}

if (type instanceof ParameterizedType pType) {
Type raw = pType.getRawType();
if (!(raw instanceof Class<?> rawClass)) {
throw new IllegalArgumentException("Unsupported raw type: " + raw);
}
if (Collection.class.isAssignableFrom(rawClass)) {
Collection<Object> collection;
if (rawClass.isInterface()) {
collection = new ArrayList<>();
} else {
collection = (Collection<Object>) rawClass.getDeclaredConstructor().newInstance();
}
Type elementType = pType.getActualTypeArguments()[0];
for (int i = 0; i < 3; i++) {
Object element = generateValueOfType(elementType, depth + 1);
collection.add(element);
}
return collection;
}
return generateType((Class<?>) rawClass, depth + 1);
}
throw new IllegalArgumentException("Unsupported type: " + type);
}

private Object generateType(Class<?> clazz, int depth) throws
InvocationTargetException,
InstantiationException,
IllegalAccessException,
NoSuchMethodException,
ClassNotFoundException
{
Constructor<?> constructor = clazz.getDeclaredConstructors()[0];

if (!clazz.isAnnotationPresent(Generatable.class)) {
throw new IllegalArgumentException("Class " + clazz.getName() + " has no Generatable annotation");
}

Type[] paramTypes = constructor.getGenericParameterTypes();
Object[] params = new Object[paramTypes.length];

for (int i = 0; i < paramTypes.length; i++) {
params[i] = generateValueOfType(paramTypes[i], depth + 1);
}

constructor.setAccessible(true);
return constructor.newInstance(params);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

У нас в целом задача -- создание разнообразных объектов случайных. Как на счет идеи пройтись по полям и случайно их сгенерировать?

}
61 changes: 61 additions & 0 deletions src/main/java/org/example/generator/MapGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package main.java.org.example.generator;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

public class MapGenerator {
private final Random random = new Random();
private final Map<Class<?>, Supplier<Object>> generators = new HashMap<>();

public MapGenerator()
{
generators.put(HashMap.class, () -> {
HashMap<String, Object> map = new HashMap<>();
fillMap(map);
return map;
});
generators.put(LinkedHashMap.class, () -> {
LinkedHashMap<String , Object> map = new LinkedHashMap<>();
fillMap(map);
return map;
});
generators.put(TreeMap.class, () -> {
TreeMap<String, Object> map = new TreeMap<>();
fillMap(map);
return map;
});
generators.put(ConcurrentHashMap.class, () -> {
ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();
fillMap(map);
return map;
});
generators.put(WeakHashMap.class, () -> {
WeakHashMap<String, Object> map = new WeakHashMap<>();
fillMap(map);
return map;
});
generators.put(IdentityHashMap.class, () -> {
IdentityHashMap<String, Object> map = new IdentityHashMap<>();
fillMap(map);
return map;
});
}

private void fillMap(Map<String, Object> map)
{
int randomSize = random.nextInt(100);
for (int i = 0; i < randomSize; i++) {
map.put(String.valueOf(i), new Object());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

На самом деле таки есть способ получить типы из коллекций вроде есть.
Подсказка -- посмотрите на наследников Type, кажется там есть ParameterizedType
Если что, поресерчьте репы некоторых одногруппников. Эта штука не самая очевидная и распространенная

Просьба потом отписать, как оно устроено и почемы мы можем получить типы несмотря на стирание

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Да, это можно сделать, проблема в том что type erasure работает на уровне рантайма, но данные остаются в метаданных обьявления переменной. Но такое не будет работать для обьектов которые созданы прям совсем на лету

Я исправил код и попробовал сгенерировать класс с джеенрик типом, результат:

Generated org.example.classes.Cart@34a245ab
With attributes:
Field items with type:interface java.util.List and value:[org.example.classes.Product@12edcd21, org.example.classes.Product@34c45dca, org.example.classes.Product@52cc8049]

Все получилось

}
}

public Map<String, Object> generate(Class<?> clazz)
{
Supplier<Object> supplier = generators.get(clazz);
if (supplier == null) {
return null;
}
return (Map<String, Object>) supplier.get();
}
}
Loading