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


import org.example.classes.BinaryTreeNode;
import org.example.classes.Cart;
import org.example.classes.Example;
import org.example.generator.Generator;
import org.example.classes.Product;
import org.example.classes.Rectangle;
import org.example.classes.Shape;
import org.example.classes.Triangle;
import org.example.generator.InstanceGenerator;

public class GenerateExample {
public static void main(String[] args) {
var gen = new Generator();
var instanceGenerator = new InstanceGenerator();
try {
Object generated = gen.generateValueOfType(Example.class);
System.out.println(generated);
var generated1 = instanceGenerator.generateValueOf(Example.class);
System.out.println(generated1);
var generated2 = instanceGenerator.generateValueOf(Cart.class);
System.out.println(generated2);
var generated3 = instanceGenerator.generateValueOf(Product.class);
System.out.println(generated3);
var generated4 = instanceGenerator.generateValueOf(Rectangle.class);
System.out.println(generated4);
var generated5 = instanceGenerator.generateValueOf(Triangle.class);
System.out.println(generated5);
var generated6 = instanceGenerator.generateValueOf(Shape.class);
System.out.println(generated6);
var generated7 = instanceGenerator.generateValueOf(BinaryTreeNode.class);
System.out.println(generated7);
} catch (Throwable e) {
throw new RuntimeException(e);
}
Expand Down
3 changes: 3 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.annotation.Generatable;

@Generatable
public class BinaryTreeNode {
private Integer data;
private BinaryTreeNode left;
Expand Down
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.annotation.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.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.generator.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.generator.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/Shape.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.example.classes;

import org.example.generator.annotation.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.annotation.Generatable;

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

import java.util.Random;

public class RandomProvider {
public static final Random RANDOM = new Random();
}
59 changes: 59 additions & 0 deletions src/main/java/org/example/generator/ClassPathScanner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.example.generator;

import org.example.generator.annotation.Generatable;

import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ClassPathScanner {

static Set<Class<?>> scanForAnnotatedClasses() {
var classpath = System.getProperty("java.class.path");
if (classpath == null || classpath.isEmpty()) {
return Collections.emptySet();
}

return Arrays.stream(classpath.split(File.pathSeparator))
.map(File::new)
.filter(File::exists)
.filter(File::isDirectory)
.flatMap(dir -> scanDirectory(dir, "").stream())
.collect(Collectors.toSet());
}

private static Set<Class<?>> scanDirectory(File dir, String targetPackage) {
var files = dir.listFiles();
if (files == null) {
return Collections.emptySet();
}

return Arrays.stream(files)
.flatMap(file -> {
if (file.isDirectory()) {
var sub = targetPackage.isEmpty() ? file.getName() : targetPackage + "." + file.getName();
return scanDirectory(file, sub).stream();
} else if (file.getName().endsWith(".class")) {
var name = targetPackage + "." + file.getName().substring(0, file.getName().length() - 6);
return tryAddClass(name).stream();
}
return Stream.empty();
})
.collect(Collectors.toSet());
}

private static Optional<Class<?>> tryAddClass(String className) {
try {
var name = Class.forName(className);
if (name.isAnnotationPresent(Generatable.class)) {
return Optional.of(name);
}
} catch (Throwable ignored) {}

return Optional.empty();
}
}
18 changes: 0 additions & 18 deletions src/main/java/org/example/generator/Generator.java

This file was deleted.

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

import org.example.common.RandomProvider;
import org.example.generator.annotation.Generatable;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

public class ImplementationIndex {

private final Set<Class<?>> annotatedTypes;
private final Map<Class<?>, List<Class<?>>> interfaceToImplementations = new HashMap<>();

public ImplementationIndex(Set<Class<?>> annotatedTypes) {
this.annotatedTypes = Objects.requireNonNull(annotatedTypes);
buildIndex();
}

public Optional<Class<?>> randomImplementationFor(Class<?> currentInterface) {
return Optional.ofNullable(interfaceToImplementations.get(currentInterface))
.filter(list -> !list.isEmpty())
.map(list -> list.get(RandomProvider.RANDOM.nextInt(list.size())));
}

private void buildIndex() {
annotatedTypes.stream()
.flatMap(currentClass -> {
Generatable annotation = currentClass.getAnnotation(Generatable.class);

if (annotation != null && annotation.implementsFor().length > 0) {
return Arrays.stream(annotation.implementsFor())
.map(target -> Map.entry(target, currentClass));
}

return Arrays.stream(currentClass.getInterfaces())
.map(currentInterface -> Map.entry(currentInterface, currentClass));
})
.forEach(entry -> register(entry.getKey(), entry.getValue()));
}

private void register(Class<?> currentInterface, Class<?> implementedClass) {
interfaceToImplementations
.computeIfAbsent(currentInterface, k -> new ArrayList<>())
.add(implementedClass);
}
}
Loading