Answer the question
In order to leave comments, you need to log in
How to make an ID for objects?
There is a need to number (give an ID) some objects, for example, like this: long id = IdService.getId(obj);
There is an idea to add all the objects in the List, then return the index of the object in the list, but here the question is immediately about the GC ... because it will not delete them and the memory will be busy ..
How to be ? P.s. objects can be from the JDK, or they can be from user code, you need an option without modifying the code, and also without using hashCode, equals (because they can be incorrectly redefined, for example in util.Set), and also without System.identity*- because there is no guarantee that the ID is unique.
Answer the question
In order to leave comments, you need to log in
It is possible to use such govnokod. The point is to create a class on the fly if it does not have an id field or it cannot be compared normally by equals and hashcode. The code needs to be tweaked, it may not work. I wrote on the fly so to speak.
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();
}
}
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question