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
58 changes: 53 additions & 5 deletions src/main/java/org/example/GenerateExample.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,63 @@
package org.example;


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

public class GenerateExample {

public static void main(String[] args) {
var gen = new Generator();
generateByDefaultGenerator();
generateByComplexGenerator();
}

private static void generateByDefaultGenerator() {
var defaultGenerator = new Generator();
try {
System.out.println(defaultGenerator.generateValueOfType(Example.class));
} catch (Throwable e) {
throw new RuntimeException(e);
}
}

private static void generateByComplexGenerator() {
var complexGenerator = new ComplexGenerator();
try {
Object generated = gen.generateValueOfType(Example.class);
System.out.println(generated);
System.out.println("------------------------------------");
System.out.println("Example.class\n");
Example exampleObj = (Example) complexGenerator.generateValueOfType(Example.class);
System.out.println(exampleObj);
System.out.println("------------------------------------");
System.out.println("Product.class\n");
Product product = (Product) complexGenerator.generateValueOfType(Product.class);
System.out.println(product.getName());
System.out.println(product.getPrice());
System.out.println("------------------------------------");
System.out.println("Triangle.class\n");
Triangle triangle = (Triangle) complexGenerator.generateValueOfType(Triangle.class);
System.out.println(triangle.getArea());
System.out.println(triangle.getPerimeter());
System.out.println("------------------------------------");
System.out.println("Rectangle.class\n");
Rectangle rectangle = (Rectangle) complexGenerator.generateValueOfType(Rectangle.class);
System.out.println(rectangle.getArea());
System.out.println(rectangle.getPerimeter());
System.out.println("------------------------------------");
System.out.println("Cart.class\n");
Cart cart = (Cart) complexGenerator.generateValueOfType(Cart.class);
System.out.println(cart.getItems());
System.out.println("------------------------------------");
System.out.println("BinaryTreeNode.class\n");
BinaryTreeNode binaryTreeNode = (BinaryTreeNode) complexGenerator.generateValueOfType(BinaryTreeNode.class);
System.out.println(binaryTreeNode.getData());
System.out.println(binaryTreeNode.getLeft());
System.out.println(binaryTreeNode.getRight());
System.out.println("------------------------------------");
System.out.println("Shape.class\n");
Shape shapeObj = (Shape) complexGenerator.generateValueOfType(Shape.class);
System.out.println(shapeObj.getPerimeter());
System.out.println(shapeObj.getArea());
System.out.println("------------------------------------");
} catch (Throwable e) {
throw new RuntimeException(e);
}
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.generator.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 +
"\n}";
}
}
3 changes: 3 additions & 0 deletions src/main/java/org/example/classes/Cart.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package org.example.classes;

import org.example.generator.Generatable;

import java.util.List;

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

Expand Down
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.generator.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.generator.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.generator.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/Shape.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.example.classes;

import org.example.generator.Generatable;

@Generatable
public interface Shape {
double getArea();
double getPerimeter();
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.generator.Generatable;

@Generatable
public class Triangle implements Shape {
private double sideA;
private double sideB;
Expand Down
115 changes: 115 additions & 0 deletions src/main/java/org/example/generator/ComplexGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package org.example.generator;

import java.lang.reflect.*;
import java.util.*;
import java.util.stream.Collectors;

public class ComplexGenerator implements IGenerator {

private static final int NUMERIC_BOUND = 1000;
private static final int BYTE_BOUND = 256;
private static final int ALPHABET_BOUND = 26;

private static final int RECURSION_BOUND = 5;
private static final int SEVERAL_VALUES_BOUND = 10;

private class RandomInvocationHandler implements InvocationHandler {

@Override
public Object invoke(Object proxy, Method method, Object[] args) {
Class<?> returnType = method.getReturnType();
return setRandomValueForParameter(returnType, returnType, 0);
}
}

@Override
public Object generateValueOfType(Class<?> clazz) {
if (!isGeneratable(clazz)) return null;
if (clazz.isInterface()) return handleInterface(clazz);
return handleClass(clazz, 0);
}

private boolean isGeneratable(Class<?> clazz) {
return !Arrays.stream(clazz.getAnnotations())
.filter(it -> it instanceof Generatable)
.collect(Collectors.toSet()).isEmpty();
}

private Object handleInterface(Class<?> iClass) {
return Proxy.newProxyInstance(
iClass.getClassLoader(),
new Class[]{iClass},
new RandomInvocationHandler()
);
}

private Object handleClass(Class<?> clazz, int recursionLevel) {
if (recursionLevel > RECURSION_BOUND) return null;
Constructor<?>[] constructors = clazz.getDeclaredConstructors();

int randomConstructorIndex = new Random().nextInt(constructors.length);
Constructor<?> randomConstructor = constructors[randomConstructorIndex];
return defineParameterTypeAndCreateObject(randomConstructor, recursionLevel);
}

private Object defineParameterTypeAndCreateObject(Constructor<?> constructor, int recursionLevel) {
Class<?>[] parameterTypes = constructor.getParameterTypes();
Type[] genericParameterTypes = constructor.getGenericParameterTypes();

Object[] parametersValues = new Object[parameterTypes.length];
for (int i = 0; i < parametersValues.length; i++) {
parametersValues[i] = setRandomValueForParameter(parameterTypes[i], genericParameterTypes[i], recursionLevel);
}
Object newInstance;
try {
newInstance = constructor.newInstance(parametersValues);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
return newInstance;
}

private Object setRandomValueForParameter(Class<?> parameterType, Type genericType, int recursionLevel) {
Random random = new Random();
if (parameterType == boolean.class || parameterType == Boolean.class) return random.nextBoolean();
if (parameterType == byte.class || parameterType == Byte.class) return random.nextInt(BYTE_BOUND);
if (parameterType == int.class || parameterType == Integer.class) return random.nextInt(NUMERIC_BOUND);
if (parameterType == long.class || parameterType == Long.class) return random.nextLong(NUMERIC_BOUND);
if (parameterType == double.class || parameterType == Double.class) return random.nextDouble(NUMERIC_BOUND);
if (parameterType == float.class || parameterType == Float.class) return random.nextFloat(NUMERIC_BOUND);
if (parameterType == char.class || parameterType == Character.class) return 'a' + random.nextInt(ALPHABET_BOUND);
if (parameterType == String.class) return generateRandomString();

int severalValuesLength = new Random().nextInt(SEVERAL_VALUES_BOUND);
if (parameterType.isArray()) {
Class<?> componentType = parameterType.getComponentType();
Object array = Array.newInstance(componentType, severalValuesLength);
for (int i = 0; i < severalValuesLength; i++) {
Array.set(array, i, handleClass(componentType, recursionLevel));
}
return array;
}

if (Collection.class.isAssignableFrom(parameterType)) {
List<Object> list = new ArrayList<>();
if (genericType instanceof ParameterizedType parameterizedType) {
Type actualTypeArgument = parameterizedType.getActualTypeArguments()[0];
Class<?> elementClass = (Class<?>) actualTypeArgument;
for (int i = 0; i < severalValuesLength; i++) {
list.add(handleClass(elementClass, recursionLevel));
}
}
return list;
}

return handleClass(parameterType, recursionLevel + 1);
}

private Object generateRandomString() {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 26; i++) {
stringBuilder.append(Character.toChars('A' + new Random().nextInt(26))[0]);
}
return stringBuilder.toString();
}
}
11 changes: 11 additions & 0 deletions src/main/java/org/example/generator/Generatable.java
Original file line number Diff line number Diff line change
@@ -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 {
}
5 changes: 2 additions & 3 deletions src/main/java/org/example/generator/Generator.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
import java.lang.reflect.InvocationTargetException;
import java.util.Random;

public class Generator {
public class Generator implements IGenerator {

@Override
public Object generateValueOfType(Class<?> clazz) throws InvocationTargetException, InstantiationException, IllegalAccessException {
Constructor<?>[] constructors = clazz.getDeclaredConstructors();

int randomConstructorIndex = new Random().nextInt(constructors.length);
Constructor<?> randomConstructor = constructors[randomConstructorIndex];
return randomConstructor.newInstance(111);
}


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

import java.lang.reflect.InvocationTargetException;

public interface IGenerator {

public Object generateValueOfType(Class<?> clazz) throws InvocationTargetException, InstantiationException, IllegalAccessException;
}