Можно использовать такой говнокод. Смысл - создавать класс на лету, если у него нет поля id или его нельзя нормально сравнить по equals и hashcode. Код надо подкрутить, он может не сработать. Писал на лету так сказать.
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.atomic.*;
public class SimpleStorage {
private Map<Integer, Object> objects = new HashMap<>();
private AtomicInteger idGenerator = new AtomicInteger(0);
private ClassMaker classMaker = new ClassMaker(0, null, null);
private static final String[] EQUALS_NOT_SUPPORTED = {}; //указать имя классов, которые не поддерживают equals и hasCode
public Integer getId(Object obj) {
Object finalObj = obj;
boolean isEqualsNotSupported = Arrays.stream(EQUALS_NOT_SUPPORTED)
.anyMatch(typeName -> finalObj.getClass().getCanonicalName().equalsIgnoreCase(typeName));
if (isEqualsNotSupported) {
final Integer id = getIdFromField(obj);
return objects.entrySet()
.stream()
.filter(entry -> id.equals(entry.getValue()))
.map(Map.Entry::getKey)
.findFirst().get();
}
Object finalObj1 = obj;
return objects.entrySet()
.stream()
.filter(entry -> finalObj1.equals(entry.getValue()))
.map(Map.Entry::getKey)
.findFirst().get();
}
public void add(Object obj) {
Integer newId = idGenerator.incrementAndGet();
obj = classMaker.createClassWithId(newId);
objects.put(newId, obj);
}
public Object get(Integer id) {
return objects.get(id);
}
private Integer getIdFromField(Object obj) {
try {
Field field = obj.getClass().getField(ClassMaker.FIELD_ID);
field.setAccessible(true);
return (Integer) field.get(obj);
} catch (NoSuchFieldException | IllegalAccessException e) {
return null;
}
}
}
import java.io.*;
import java.net.*;
import java.util.*;
import javax.tools.*;
public class ClassMaker {
public static final String FIELD_ID = "id";
private Integer id = 0;
private String className;
private String sourceCode;
private File sourceFile;
public ClassMaker(Integer id, String className, String sourceCode) {
this.id = id;
this.className = className;
this.sourceCode = sourceCode;
}
public Object createClassWithId(Integer id) {
if (id != null)
this.id = id;
sourceCode = createSimpleString(id);
Object obj = null;
try (FileWriter writer = new FileWriter(createTmpFile())) {
writer.write(sourceCode);
compileClass();
className = sourceFile.getName().split("\\.")[0];
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[]{sourceFile.getParentFile().toURI().toURL()});
Class<?> newClass = classLoader.loadClass(className);
obj = newClass.newInstance();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
return obj;
}
private void compileClass() throws IOException {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
File parentDirectory = sourceFile.getParentFile();
fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singletonList(parentDirectory));
Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(Collections.singletonList(sourceFile));
compiler.getTask(null, fileManager, null, null, null, compilationUnits).call();
fileManager.close();
}
private File createTmpFile() throws IOException {
File sourceFile = File.createTempFile(className, ".java");
sourceFile.deleteOnExit();
this.sourceFile = sourceFile;
return sourceFile;
}
private String createSimpleString(Integer id) {
StringBuilder classBuilder = new StringBuilder();
classBuilder.append("public class ")
.append(className)
.append(" {")
.append("private Integer id = ")
.append(id)
.append(";")
.append(" public void setId(Integer id) {\n")
.append(" this.id = id;\n").append(" }\n")
.append("\n").append(" public Integer getId() {\n")
.append(" return id;\n")
.append(" }").append(" @Override\n")
.append(" public boolean equals(Object o) {\n")
.append(" if (this == o) return true;\n")
.append(" if (o == null || getClass() != o.getClass()) return false;\n")
.append("\n")
.append(className)
.append(" that = ")
.append("(").append(className).append(")").append(" o;")
.append("\n")
.append(" return id != null ? id.equals(that.id) : that.id == null;\n")
.append(" }\n").append("\n").append(" @Override\n")
.append(" public int hashCode() {\n")
.append(" return id != null ? id.hashCode() : 0;\n")
.append(" }\n")
.append("}");
return classBuilder.toString();
}
}
А вообще странная задача - давать всем уникальные id. Откуда объекты берутся? Почему нельзя инкапсулировать всякие сеты и листы внутри пользовательских классов?