S
S
synapse_people2018-09-07 13:10:46
Java
synapse_people, 2018-09-07 13:10:46

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

2 answer(s)
N
nubus4000, 2018-09-07
@synapse_people

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();
    }
}

In general, a strange task is to give everyone unique id. Where do objects come from? Why is it impossible to encapsulate all sorts of sets and sheets inside custom classes?

F
FRF, 2018-09-07
@frf_nn

* for GC to remove, you can use WeakReference
* for ID, you can use UUID

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question