Search code examples
javajpaeclipselink

Any reason to initialize Entity properties with synchronized Collections?


For JPA-Entities in a project I work on, properties of type List or Map are always initialized to the synchronized implementations Vector and Hashtable.
(Unsynchronized ArrayList and HashMap are the standard implementations in Java, except if synchronization is really needed.)

Does anyone know a reason why synchronized Collections would be needed? We use EclipseLink.


When I asked about it, nobody knew why it was done like that. It seems it was always done like this. Maybe this was needed for an old version of EclipseLink?


I'm asking for two reasons:

  • I would prefer to use the standard implementations ArrayList and HashMap like anywhere else. If that's safe.
  • There's no matching synchronized Set implementation in the JDK. At least not a serializable one as EclipseLink expects.

Example Entity:

@Entity
public class Person {
    ...

    @ManyToMany(cascade=CascadeType.ALL)
    @JoinTable( ... )
    private List<Role> accessRoles;


    @ElementCollection
    @CollectionTable( ... )
    @MapKeyColumn(name="KEY")
    @Column(name="VALUE")
    private Map<String, String> attrs;

    public Person() {
        // Why Vector/Hashtable instead of ArrayList/HashMap?
        accessRoles = new Vector<Role>();
        attrs = new Hashtable<String, String>();
    }

    public List<Role> getAccessRoles() {
        return accessRoles;
    }

    public void setAccessRoles(List<Role> accessRoles) {
        this.accessRoles = accessRoles;
    }

    public Map<String, String> getAttrs() {
        return attrs;
    }

    public void setAttrs(Map<String, String> attrs) {
        this.attrs = attrs;
    }
}

Solution

  • There's usually no need for a Vector and an ArrayList is more commonly used. So if your current codebase is full of Vectors, this is a bit of a code smell and it is wise to make sure your team members know what the difference is. See also What are the differences between ArrayList and Vector? and Why is Java Vector class considered obsolete or deprecated?

    That does not mean you should do the Big Cleanup and replace all the Vectors in your existing code with ArrayLists.

    • Your code uses Lists and you won't notice a single difference when programming.
    • The only advantage to be expected is increased performance.
    • It is hard to tell if none of your code depends on the synchronization provided by the Vectors.

    So, unless you are currently suffering performance issues, or are explicitly (re)designing the synchronization of your entire codebase, you risk introducing hard to fix concurrency bugs without any benefits.

    Also, be aware that performance suffers most significantly from the use of Vectors when multiple threads access your collections concurrently. So if you are suffering from performance loss and decide to replace the Vectors for that reason, you'll need to be very careful to keep access sufficiently synchronized.


    EDIT: You ask about EclipseLink JPA specifically.

    It'd be rather surprising if they demanded you use Vectors and Hashtables since that would mean they ask you to rely on obsolete data structures. In their examples, they use ArrayLists and HashMaps so from that we may conclude that this is indeed not the case.

    Diving a bit more specifically into the source code, we can see that their CollectionContainerPolicy uses the Collection interface and does not care about the implementation of your collections. It does, however, surprisingly have special cases for when your internal collection class is Vector. See for instance buildContainerFromVector. And its default container class is Vector, though you can alter that.

    See also the documentation for the Container policy.

    The most intrusive moment where EclipseLink and your Lists meet is when you're lazy loading collections. EclipseLink will replace the collection with its own IndirectList which internally uses a Vector. See What collections does jpa return? So in those cases, EclipseLink will give you a Vector anyways(!) and it does not even matter what collection you specify in the collection's initialization.

    So EclipseLink indeed has a preference for using Vectors and using Vectors with EclipseLink means less copying of object references from one collection to the other.