Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to have hibernate use String.intern on attributes

Tags:

java

hibernate

For some entities we need to keep loads (thousands) of detached enties permanently in memory. Many of their attributes are from a limited set of strings (though not limited enough to put it into an enumeration). Is it possible to have hibernate use String.intern for those attributes to save space?

Ideally that should work via an annotation I could put on each of those attributes, or something easily changeable, without confusing the source code too much by this implementation concern.

like image 552
Hans-Peter Störr Avatar asked Jul 24 '15 09:07

Hans-Peter Störr


People also ask

What is intern () in String?

The method intern() creates an exact copy of a String object in the heap memory and stores it in the String constant pool. Note that, if another String with the same contents exists in the String constant pool, then a new object won't be created and the new reference will point to the other String.

What is the use of the intern () method it creates a new String in database?

The intern() method creates an exact copy of a string that is present in the heap memory and stores it in the String constant pool if not already present. If the string is already present, it returns the reference. The intern() method helps to save memory space and reuse it efficiently at the cost of time.

What is String intern () When and why should it be used?

String Interning is a method of storing only one copy of each distinct String Value, which must be immutable. By applying String. intern() on a couple of strings will ensure that all strings having the same contents share the same memory.

Does Java automatically intern strings?

intern() in Java. All compile-time constant strings in Java are automatically interned using this method. String interning is supported by some modern object-oriented programming languages, including Java, Python, PHP (since 5.4), Lua,Julia and .


2 Answers

As you suggest yourself, it's perfectly doable with a JPA attribute converter. You could do it on a general level by using autoApply = true on the converter, or you could do it on a field by field level with the @Convert annotation.

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter(autoApply = true)
public class StringInternConverter implements AttributeConverter<String, String> {
    @Override
    public String convertToDatabaseColumn(String attribute) {
        return attribute;
    }

    @Override
    public String convertToEntityAttribute(String dbData) {
        return dbData != null? dbData.intern(): null;
    }
}

Tested with Hibernate 5.2.10 and works like a charm!

like image 68
Per Huss Avatar answered Nov 07 '22 06:11

Per Huss


1) You can use property access for the critical properties and intern the strings in the setters:

public void setFoo(String foo) {
   this.foo = foo != null ? foo.intern() : null;
}

2) If the above solution is tedious (you may have lots of such String properties), then you could register a Hibernate interceptor and intern all of the String fields using reflection:

for (Field field : getDeclaredFields(entity)) {
    if (!isStaticOrFinal(field)) {
        field.setAccessible(true);
        Object value = field.get(entity);
        if (value instanceof String) {
            field.set(entity, ((String) value).intern());
        }
    }
}

private List<Field> getDeclaredFields(Object object) {
    List<Field> result = new ArrayList<Field>(Arrays.asList(object.getClass().getDeclaredFields()));
    for (Class<?> superclass = object.getClass().getSuperclass(); superclass != null; superclass = superclass.getSuperclass()) {
        result.addAll(Arrays.asList(superclass.getDeclaredFields()));
    }
    return result;
}

private boolean isStaticOrFinal(Field field) {
    return ((Modifier.STATIC | Modifier.FINAL) & field.getModifiers()) != 0;
}

You can execute this in the onSave and onLoad interceptor methods.

like image 34
Dragan Bozanovic Avatar answered Nov 07 '22 07:11

Dragan Bozanovic