Can I mark object field as unique in Java - java

As in the subject Can I mark object field as unique in Java? I want to have unique id in the class.

You can create unique IDs with a static variable which you increment on each object creation and assign to your ID variable:
private static int globalID = 0;
private int ID;
public obj()
{
globalID++;
this.ID = globalID;
}

No, that is not possible. You have to manage that in a Controller class.

Your question was a bit vague, but I am going to attempt to answer it based on the limited information.
I want to have unique id in the class.
If you are looking to specify a Unique ID for the class for persistence through a well-known framework such as Hibernate, you can do so through the HBM mapping or #Id annotation.
If you are looking to ensure that an instance of a particular Class is unique (from a runtime perspective), then you should override the .equals method and do the comparison in .equals based on the field that you are using as the "unique id of the class". If you wanted some sort of development-time indicator that particular field is your "unique ID", you could always create a custom annotation.
Here is an excellet answer from a different StackOverflow post regarding how to override .equals and .hashCode using the Apache Commons Lang library. You can use this and just modify the .equals override to compare on whatever field you are using as your "Unique ID".

When you don't care about the content of your unique field except for the fact that they have to be unique, you can use the solution by nukebauer.
But when you want to set the value manually and throw an exception when the value is already used by another instance of the class, you can keep track of the assigned values in a static set:
class MyObject {
private Integer id;
private static Set<Integer> assignedIds = new HashSet<Integer>();
public void setId(int id) throws NotUniqueException {
if (!this.id.equals(id) {
if (assignedIds.contains(id) {
throw new NotUniqueException();
}
assignedIds.add(id);
this.id = id;
}
}
}
By the way: Note that both options are not thread-safe! That means that when two threads create an instance / set an ID at exactly the same time, they might still get the same ID. When you want to use this in a multi-threading environment, you should wrap the code in a synchronized block which synchronizes on the static variable.

Related

How to use an object's class variables to identify an object in java?

I created a class and made 57 objects from it, each one has specific ID number.
Can I create a method which returns an object using an ID as the argument?
For example, assume the name of my class is Things and I made two object from it called apple and dog, they have IDs 1 and 2.
Things.java:
class Things {
private String name;
private int ID;
public Things(String name, int ID) {
this.name = name;
this.ID = ID;
}
}
Main.java:
class Main {
public static void main(String[] args) {
Things apple = new Things("apple", 1);
Things dog = new Things("dog", 2);
}
}
in this example I want to create a method in class "Things" which returns object apple if I use 1 as argument and object dog if I use 2 .
You cannot identify objects by a particular property unless you store it in a special repository
You can create a ThingRepository and can get specific Things by the id.
public class ThingRepository {
private Map<Integer, Things> thingsRepository = new HashMap<>();
public void addThing(int id, Things things) {
thingsRepository.put(id, things);
}
public Things getThingById(int id) {
return thingsRepository.get(id); //Can return null if not present
}
}
The addThing method need not explicitly take the id. If you add a getter to Things, then it can be simplified to
public void addThing(Things things) {
thingsRepository.put(things.getId(), things);
}
Couple of problems you need to address:
Each created Things object has to be added to this somehow (either the caller needs to add or there must be some other wrapper/factory that must do this).
Once a Things is not needed, it must be removed from the above map, else it can lead to memory leak.
Btw, shouldn't Things be named as just a Thing?
There are two aspects here:
you need some sort of data structure that remembers about created objects, and allows you to access them by id, for example a simple Map<Integer, Things>. Each time you create a new Things (should better be called Thing, shouldn't it?!), you go thatMap.put(newId, newThing).
if you want that data to "survive", you would have to somehow persist it (like writing data to a file, database, ...)
If you use Intellij for example press: alt + insert and choose getters/setter.
If not just write your own getters/setter ;).
Like here: https://docs.oracle.com/javaee/6/tutorial/doc/gjbbp.html
But basically if you want to look for Thing with particular Id you need to store somewhere them for example in ArrayList, then iterate through it and if your find element with that Id just return it.
1) Create new ArrayList
2) Iterate through
3) If you find Thing with Id you want, return it.

how to insure a certain field in a class has different and unique values in all instances in java?

I'm new to coding and I've faced this problem recently: I'm working on a class which has various fields, and I want to insure each instance of the class has a unique value for a certain field using static variables. for example, consider this class:
public class NetworkNode {
private String NodeName;
private int NodeNumber;
private boolean NodeAttraction;
....
}
in the code above, I want to insure each object created from the class NetworkNode to have a unique and different NodeNumber or in other words, no two NetworkNode objects should have the same NodeNumber field.
what are the ways to do this? thanks.
You could automatically assign a different NodeNumber to each instance if you don't care about the actual value as long as it's unique. Using static variables you could create a private static counter nextNodeNumber in your class NetworkNode:
private static int nextNodeNumber = 0;
In your constructor you could then do
public NetworkNode() {
this.NodeNumber = nextNodeNumber;
++nextNodeNumber;
...
}
This way you just have to ensure, that there is no other way to set/change NodeNumber or nextNodeNumber.
If you are using multiple Threads you would have to secure access to nextNodeNumber to prevent asynchronous access.
1 put a
static Set<String> myuniquevalues ... (for example) for each of your fields
2 in your constructor
public NetworkNode (String value1 ...)
{... check if value1 exists in myuniquevalues , and throw exceptions }
3 if your objects are deleted, you must manage it also ...
Alternative: concentrate creation of your objects in a factory, and manage unicity there.
I recommend you to do some reading about variables and what static means. To make it short, a static variable exists only "once" in your program.
For example, if you create a game, you want the variable score to be static since there will only be one instance of this variable.
In order to have each NetworkNode to have a unique and different NodeNumber, you have to construct the object like this:
public NetworkNode(String NodeName, int NodeNumber, boolean NodeAttraction){
this.NodeName = NodeName;
this.NodeNumber = NodeNumber;
this.NodeAttraction = NodeAttraction;
}
See, here, each NetworkNode will have a different value for each of the variables passed as parameters.
You will then just need to create the object in your main function or whatever like this for example:
NetworkNode myNode = new NetworkNode("node1", 0, true);
Hope it helps,

How to make a specific parameter unique in Java

How can I make sure that each instance of a class will have a unique value for a specific parameter?
For example:
public Foo(int value);
value should be different for each instance of Foo. Otherwise, it can throw an exception.
Do you want to assign that value, or do you just want to make sure you have some kind of id?
A minimal solution for an id would be to use a static field as counter:
public class Foo {
private static int counter = 1;
private int id;
public Foo() {
id = counter++;
}
}
To check for assigned values you might want to use some kind of FooFactory:
public class FooFactory {
private static Set<int> ids = new Set<int>();
public static Foo createFoo(int value) {
if (ids.contains(value)) {
throw new FooAlreadyExistsException();
}
ids.add(value);
return new Foo(value);
}
}
Or, as other comments suggest, you could do this in the Foo constructor:
public class Foo {
private static Set<int> ids = new Set<int>();
public Foo(int value) {
if (ids.contains(value)) {
throw new FooAlreadyExistsException();
}
ids.add(value);
}
}
Create a factory:
public Foo createFoo( int value ) {....}
In the factory code, you can maintain a set of "allocated" values. This allows you to optimize the code; for example if the values are consecutive, a BitSet might be better than Set<Integer>. Note that you must "deallocate" your instances of Foo somehow if you want to be able to reuse values.
If you just GC instances of Foo, the value will still be "in use" unless you notify the factory somehow.
Assuming all instances of Foo would be in memory, you can maintain a static Set in the Foo class that would hold the values that were already used. You can check against this Set any time a new instance is created.
Another alternative, assuming there is no functional meaning to this value, is to have some sequence (backed by either a DB or a file) that would increment any time a new instance is created, and the value of each new instance would be the current value of that sequence.
I think your unique value should not be a parameter (which is under control of an arbitrary caller) but a responsibility of Foo.
A simple solution would be to use a static field which is incremented each time an instance is created:
private static int instanceCounter;
// instance initializer
{
instanceCounter++;
}
As others have mentioned this smells of a problem in your design or your understanding of the requirements.
Please share the requirements, your intended design and the code you have created so far.
EDIT: 'Aaron Digulla' has a better suggestion, to create a factory which manages this aspect of the object lifecycle.
I'd propose having a static ArrayList inside of a class, containing a list of your objects. But this is bad design IMHO.

The JPA hashCode() / equals() dilemma

There have been some discussions here about JPA entities and which hashCode()/equals() implementation should be used for JPA entity classes. Most (if not all) of them depend on Hibernate, but I'd like to discuss them JPA-implementation-neutrally (I am using EclipseLink, by the way).
All possible implementations are having their own advantages and disadvantages regarding:
hashCode()/equals() contract conformity (immutability) for List/Set operations
Whether identical objects (e.g. from different sessions, dynamic proxies from lazily-loaded data structures) can be detected
Whether entities behave correctly in detached (or non-persisted) state
As far I can see, there are three options:
Do not override them; rely on Object.equals() and Object.hashCode()
hashCode()/equals() work
cannot identify identical objects, problems with dynamic proxies
no problems with detached entities
Override them, based on the primary key
hashCode()/equals() are broken
correct identity (for all managed entities)
problems with detached entities
Override them, based on the Business-Id (non-primary key fields; what about foreign keys?)
hashCode()/equals() are broken
correct identity (for all managed entities)
no problems with detached entities
My questions are:
Did I miss an option and/or pro/con point?
What option did you choose and why?
UPDATE 1:
By "hashCode()/equals() are broken", I mean that successive hashCode() invocations may return differing values, which is (when correctly implemented) not broken in the sense of the Object API documentation, but which causes problems when trying to retrieve a changed entity from a Map, Set or other hash-based Collection. Consequently, JPA implementations (at least EclipseLink) will not work correctly in some cases.
UPDATE 2:
Thank you for your answers -- most of them have remarkable quality.
Unfortunately, I am still unsure which approach will be the best for a real-life application, or how to determine the best approach for my application. So, I'll keep the question open and hope for some more discussions and/or opinions.
Read this very nice article on the subject: Don't Let Hibernate Steal Your Identity.
The conclusion of the article goes like this:
Object identity is deceptively hard to implement correctly when
objects are persisted to a database. However, the problems stem
entirely from allowing objects to exist without an id before they are
saved. We can solve these problems by taking the responsibility of
assigning object IDs away from object-relational mapping frameworks
such as Hibernate. Instead, object IDs can be assigned as soon as the
object is instantiated. This makes object identity simple and
error-free, and reduces the amount of code needed in the domain model.
I always override equals/hashcode and implement it based on the business id. Seems the most reasonable solution for me. See the following link.
To sum all this stuff up, here is a listing of what will work or won't work with the different ways to handle equals/hashCode:
EDIT:
To explain why this works for me:
I don't usually use hashed-based collection (HashMap/HashSet) in my JPA application. If I must, I prefer to create UniqueList solution.
I think changing business id on runtime is not a best practice for any database application. On rare cases where there is no other solution, I'd do special treatment like remove the element and put it back to the hashed-based collection.
For my model, I set the business id on constructor and doesn't provide setters for it. I let JPA implementation to change the field instead of the property.
UUID solution seems to be overkill. Why UUID if you have natural business id? I would after all set the uniqueness of the business id in the database. Why having THREE indexes for each table in the database then?
I personally already used all of these three stategies in different projects. And I must say that option 1 is in my opinion the most practicable in a real life app. In my experience breaking hashCode()/equals() conformity leads to many crazy bugs as you will every time end up in situations where the result of equality changes after an entity has been added to a collection.
But there are further options (also with their pros and cons):
a) hashCode/equals based on a set of immutable, not null, constructor assigned, fields
(+) all three criterias are guaranteed
(-) field values must be available to create a new instance
(-) complicates handling if you must change one of then
b) hashCode/equals based on a primary key that is assigned by the application (in the constructor) instead of JPA
(+) all three criterias are guaranteed
(-) you cannot take advantage of simple reliable ID generation stategies like DB sequences
(-) complicated if new entities are created in a distributed environment (client/server) or app server cluster
c) hashCode/equals based on a UUID assigned by the constructor of the entity
(+) all three criterias are guaranteed
(-) overhead of UUID generation
(-) may be a little risk that twice the same UUID is used, depending on algorythm used (may be detected by an unique index on DB)
If you want to use equals()/hashCode() for your Sets, in the sense that the same entity can only be in there once, then there is only one option: Option 2. That's because a primary key for an entity by definition never changes (if somebody indeed updates it, it's not the same entity anymore)
You should take that literally: Since your equals()/hashCode() are based on the primary key, you must not use these methods, until the primary key is set. So you shouldn't put entities in the set, until they're assigned a primary key. (Yes, UUIDs and similar concepts may help to assign primary keys early.)
Now, it's theoretically also possible to achieve that with Option 3, even though so-called "business-keys" have the nasty drawback that they can change: "All you'll have to do is delete the already inserted entities from the set(s), and re-insert them." That is true - but it also means, that in a distributed system, you'll have to make sure, that this is done absolutely everywhere the data has been inserted to (and you'll have to make sure, that the update is performed, before other things occur). You'll need a sophisticated update mechanism, especially if some remote systems aren't currently reachable...
Option 1 can only be used, if all the objects in your sets are from the same Hibernate session. The Hibernate documentation makes this very clear in chapter 13.1.3. Considering object identity:
Within a Session the application can safely use == to compare objects.
However, an application that uses == outside of a Session might produce unexpected results. This might occur even in some unexpected places. For example, if you put two detached instances into the same Set, both might have the same database identity (i.e., they represent the same row). JVM identity, however, is by definition not guaranteed for instances in a detached state. The developer has to override the equals() and hashCode() methods in persistent classes and implement their own notion of object equality.
It continues to argue in favor of Option 3:
There is one caveat: never use the database identifier to implement equality. Use a business key that is a combination of unique, usually immutable, attributes. The database identifier will change if a transient object is made persistent. If the transient instance (usually together with detached instances) is held in a Set, changing the hashcode breaks the contract of the Set.
This is true, if you
cannot assign the id early (e.g. by using UUIDs)
and yet you absolutely want to put your objects in sets while they're in transient state.
Otherwise, you're free to choose Option 2.
Then it mentions the need for a relative stability:
Attributes for business keys do not have to be as stable as database primary keys; you only have to guarantee stability as long as the objects are in the same Set.
This is correct. The practical problem I see with this is: If you can't guarantee absolute stability, how will you be able to guarantee stability "as long as the objects are in the same Set". I can imagine some special cases (like using sets only for a conversation and then throwing it away), but I would question the general practicability of this.
Short version:
Option 1 can only be used with objects within a single session.
If you can, use Option 2. (Assign PK as early as possible, because you can't use the objects in sets until the PK is assigned.)
If you can guarantee relative stability, you can use Option 3. But be careful with this.
We usually have two IDs in our entities:
Is for persistence layer only (so that persistence provider and database can figure out relationships between objects).
Is for our application needs (equals() and hashCode() in particular)
Take a look:
#Entity
public class User {
#Id
private int id; // Persistence ID
private UUID uuid; // Business ID
// assuming all fields are subject to change
// If we forbid users change their email or screenName we can use these
// fields for business ID instead, but generally that's not the case
private String screenName;
private String email;
// I don't put UUID generation in constructor for performance reasons.
// I call setUuid() when I create a new entity
public User() {
}
// This method is only called when a brand new entity is added to
// persistence context - I add it as a safety net only but it might work
// for you. In some cases (say, when I add this entity to some set before
// calling em.persist()) setting a UUID might be too late. If I get a log
// output it means that I forgot to call setUuid() somewhere.
#PrePersist
public void ensureUuid() {
if (getUuid() == null) {
log.warn(format("User's UUID wasn't set on time. "
+ "uuid: %s, name: %s, email: %s",
getUuid(), getScreenName(), getEmail()));
setUuid(UUID.randomUUID());
}
}
// equals() and hashCode() rely on non-changing data only. Thus we
// guarantee that no matter how field values are changed we won't
// lose our entity in hash-based Sets.
#Override
public int hashCode() {
return getUuid().hashCode();
}
// Note that I don't use direct field access inside my entity classes and
// call getters instead. That's because Persistence provider (PP) might
// want to load entity data lazily. And I don't use
// this.getClass() == other.getClass()
// for the same reason. In order to support laziness PP might need to wrap
// my entity object in some kind of proxy, i.e. subclassing it.
#Override
public boolean equals(final Object obj) {
if (this == obj)
return true;
if (!(obj instanceof User))
return false;
return getUuid().equals(((User) obj).getUuid());
}
// Getters and setters follow
}
EDIT: to clarify my point regarding calls to setUuid() method. Here's a typical scenario:
User user = new User();
// user.setUuid(UUID.randomUUID()); // I should have called it here
user.setName("Master Yoda");
user.setEmail("yoda#jedicouncil.org");
jediSet.add(user); // here's bug - we forgot to set UUID and
//we won't find Yoda in Jedi set
em.persist(user); // ensureUuid() was called and printed the log for me.
jediCouncilSet.add(user); // Ok, we got a UUID now
When I run my tests and see the log output I fix the problem:
User user = new User();
user.setUuid(UUID.randomUUID());
Alternatively, one can provide a separate constructor:
#Entity
public class User {
#Id
private int id; // Persistence ID
private UUID uuid; // Business ID
... // fields
// Constructor for Persistence provider to use
public User() {
}
// Constructor I use when creating new entities
public User(UUID uuid) {
setUuid(uuid);
}
... // rest of the entity.
}
So my example would look like this:
User user = new User(UUID.randomUUID());
...
jediSet.add(user); // no bug this time
em.persist(user); // and no log output
I use a default constructor and a setter, but you may find two-constructors approach more suitable for you.
If you have a business key, then you should use that for equals and hashCode.
If you don't have a business key, you should not leave it with the default Object equals and hashCode implementations because that does not work after you merge and entity.
You can use the entity identifier in the equals method only if the hashCode implementation returns a constant value, like this:
#Entity
public class Book implements Identifiable<Long> {
#Id
#GeneratedValue
private Long id;
private String title;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Book)) return false;
Book book = (Book) o;
return getId() != null && Objects.equals(getId(), book.getId());
}
#Override
public int hashCode() {
return getClass().hashCode();
}
//Getters and setters omitted for brevity
}
Check out this test case on GitHub that proves this solution works like a charm.
Although using a business key (option 3) is the most commonly recommended approach (Hibernate community wiki, "Java Persistence with Hibernate" p. 398), and this is what we mostly use, there's a Hibernate bug which breaks this for eager-fetched sets: HHH-3799. In this case, Hibernate can add an entity to a set before its fields are initialized. I'm not sure why this bug hasn't gotten more attention, as it really makes the recommended business-key approach problematic.
I think the heart of the matter is that equals and hashCode should be based on immutable state (reference Odersky et al.), and a Hibernate entity with Hibernate-managed primary key has no such immutable state. The primary key is modified by Hibernate when a transient object becomes persistent. The business key is also modified by Hibernate, when it hydrates an object in the process of being initialized.
That leaves only option 1, inheriting the java.lang.Object implementations based on object identity, or using an application-managed primary key as suggested by James Brundege in "Don't Let Hibernate Steal Your Identity" (already referenced by Stijn Geukens's answer) and by Lance Arlaus in "Object Generation: A Better Approach to Hibernate Integration".
The biggest problem with option 1 is that detached instances can't be compared with persistent instances using .equals(). But that's OK; the contract of equals and hashCode leaves it up to the developer to decide what equality means for each class. So just let equals and hashCode inherit from Object. If you need to compare a detached instance to a persistent instance, you can create a new method explicitly for that purpose, perhaps boolean sameEntity or boolean dbEquivalent or boolean businessEquals.
I agree with Andrew's answer. We do the same thing in our application but instead of storing UUIDs as VARCHAR/CHAR, we split it into two long values. See UUID.getLeastSignificantBits() and UUID.getMostSignificantBits().
One more thing to consider, is that calls to UUID.randomUUID() are pretty slow, so you might want to look into lazily generating the UUID only when needed, such as during persistence or calls to equals()/hashCode()
#MappedSuperclass
public abstract class AbstractJpaEntity extends AbstractMutable implements Identifiable, Modifiable {
private static final long serialVersionUID = 1L;
#Version
#Column(name = "version", nullable = false)
private int version = 0;
#Column(name = "uuid_least_sig_bits")
private long uuidLeastSigBits = 0;
#Column(name = "uuid_most_sig_bits")
private long uuidMostSigBits = 0;
private transient int hashCode = 0;
public AbstractJpaEntity() {
//
}
public abstract Integer getId();
public abstract void setId(final Integer id);
public boolean isPersisted() {
return getId() != null;
}
public int getVersion() {
return version;
}
//calling UUID.randomUUID() is pretty expensive,
//so this is to lazily initialize uuid bits.
private void initUUID() {
final UUID uuid = UUID.randomUUID();
uuidLeastSigBits = uuid.getLeastSignificantBits();
uuidMostSigBits = uuid.getMostSignificantBits();
}
public long getUuidLeastSigBits() {
//its safe to assume uuidMostSigBits of a valid UUID is never zero
if (uuidMostSigBits == 0) {
initUUID();
}
return uuidLeastSigBits;
}
public long getUuidMostSigBits() {
//its safe to assume uuidMostSigBits of a valid UUID is never zero
if (uuidMostSigBits == 0) {
initUUID();
}
return uuidMostSigBits;
}
public UUID getUuid() {
return new UUID(getUuidMostSigBits(), getUuidLeastSigBits());
}
#Override
public int hashCode() {
if (hashCode == 0) {
hashCode = (int) (getUuidMostSigBits() >> 32 ^ getUuidMostSigBits() ^ getUuidLeastSigBits() >> 32 ^ getUuidLeastSigBits());
}
return hashCode;
}
#Override
public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
if (!(obj instanceof AbstractJpaEntity)) {
return false;
}
//UUID guarantees a pretty good uniqueness factor across distributed systems, so we can safely
//dismiss getClass().equals(obj.getClass()) here since the chance of two different objects (even
//if they have different types) having the same UUID is astronomical
final AbstractJpaEntity entity = (AbstractJpaEntity) obj;
return getUuidMostSigBits() == entity.getUuidMostSigBits() && getUuidLeastSigBits() == entity.getUuidLeastSigBits();
}
#PrePersist
public void prePersist() {
// make sure the uuid is set before persisting
getUuidLeastSigBits();
}
}
Jakarta Persistence 3.0, section 4.12 writes:
Two entities of the same abstract schema type are equal if and only if they have the same primary key value.
I see no reason why Java code should behave differently.
If the entity class is in a so called "transient" state, i.e. it's not yet persisted and it has no identifier, then the hashCode/equals methods can not return a value, they ought to blow up, ideally implicitly with a NullPointerException when the method attempts to traverse the ID. Either way, this will effectively stop application code from putting a non-managed entity into a hash-based data structure. In fact, why not go one step further and blow up if the class and identifier are equal, but other important attributes such as the version are unequal (IllegalStateException)! Fail-fast in a deterministic way is always the preferred option.
Word of caution: Also document the blowing-up behavior. Documentation is important in and by itself, but it will hopefully also stop junior developers in the future to do something stupid with your code (they have this tendency to suppress NullPointerException where it happened and the last thing on their mind is side-effects lol).
Oh, and always use getClass() instead of instanceof. The equals-method requires symmetry. If b is equal to a, then a must be equal to b. With subclasses, instanceof breaks this relationship (a is not instance of b).
Although I personally always use getClass() even when implementing non-entity classes (the type is state, and so a subclass adds state even if the subclass is empty or only contains behavior), instanceof would've been fine only if the class is final. But entity classes must not be final (ยง2.1) so we're really out of options here.
Some folks may not like getClass(), because of the persistence provider's proxy wrapping the object. This might have been a problem in the past, but it really shouldn't be. A provider not returning different proxy classes for different entities, well, I'd say that's not a very smart provider lol. Generally, we shouldn't solve a problem until there is a problem. And, it seems like Hibernate's own documentation doesn't even see it worthwhile mentioning. In fact, they elegantly use getClass() in their own examples (see this).
Lastly, if one has an entity subclass that is an entity, and the inheritance mapping strategy used is not the default ("single table"), but configured to be a "joined subtype", then the primary key in that subclass table will be the same as the superclass table. If the mapping strategy is "table per concrete class", then the primary key may be the same as in the superclass. An entity subclass is very likely to be adding state and therefore just as likely to be logically a different thing. But an equals implementation using instanceof can not necessarily and secondarily rely on the ID only, as we saw may be the same for different entities.
In my opinion, instanceof has no place at all in a non-final Java class, ever. This is especially true for persistent entities.
There are obviously already very informative answers here but I will tell you what we do.
We do nothing (ie do not override).
If we do need equals/hashcode to work for collections we use UUIDs.
You just create the UUID in the constructor. We use http://wiki.fasterxml.com/JugHome for UUID. UUID is a little more expensive CPU wise but is cheap compared to serialization and db access.
Please consider the following approach based on predefined type identifier and the ID.
The specific assumptions for JPA:
entities of the same "type" and the same non-null ID are considered equal
non-persisted entities (assuming no ID) are never equal to other entities
The abstract entity:
#MappedSuperclass
public abstract class AbstractPersistable<K extends Serializable> {
#Id #GeneratedValue
private K id;
#Transient
private final String kind;
public AbstractPersistable(final String kind) {
this.kind = requireNonNull(kind, "Entity kind cannot be null");
}
#Override
public final boolean equals(final Object obj) {
if (this == obj) return true;
if (!(obj instanceof AbstractPersistable)) return false;
final AbstractPersistable<?> that = (AbstractPersistable<?>) obj;
return null != this.id
&& Objects.equals(this.id, that.id)
&& Objects.equals(this.kind, that.kind);
}
#Override
public final int hashCode() {
return Objects.hash(kind, id);
}
public K getId() {
return id;
}
protected void setId(final K id) {
this.id = id;
}
}
Concrete entity example:
static class Foo extends AbstractPersistable<Long> {
public Foo() {
super("Foo");
}
}
Test example:
#Test
public void test_EqualsAndHashcode_GivenSubclass() {
// Check contract
EqualsVerifier.forClass(Foo.class)
.suppress(Warning.NONFINAL_FIELDS, Warning.TRANSIENT_FIELDS)
.withOnlyTheseFields("id", "kind")
.withNonnullFields("id", "kind")
.verify();
// Ensure new objects are not equal
assertNotEquals(new Foo(), new Foo());
}
Main advantages here:
simplicity
ensures subclasses provide type identity
predicted behavior with proxied classes
Disadvantages:
Requires each entity to call super()
Notes:
Needs attention when using inheritance. E.g. instance equality of class A and class B extends A may depend on concrete details of the application.
Ideally, use a business key as the ID
Looking forward to your comments.
I have always used option 1 in the past because I was aware of these discussions and thought it was better to do nothing until I knew the right thing to do. Those systems are all still running successfully.
However, next time I may try option 2 - using the database generated Id.
Hashcode and equals will throw IllegalStateException if the id is not set.
This will prevent subtle errors involving unsaved entities from appearing unexpectedly.
What do people think of this approach?
Business keys approach doesn't suit for us. We use DB generated ID, temporary transient tempId and override equal()/hashcode() to solve the dilemma. All entities are descendants of Entity. Pros:
No extra fields in DB
No extra coding in descendants entities, one approach for all
No performance issues (like with UUID), DB Id generation
No problem with Hashmaps (don't need to keep in mind the use of equal & etc.)
Hashcode of new entity doesn't changed in time even after persisting
Cons:
There are may be problems with serializing and deserializing not persisted entities
Hashcode of the saved entity may change after reloading from DB
Not persisted objects considered always different (maybe this is right?)
What else?
Look at our code:
#MappedSuperclass
abstract public class Entity implements Serializable {
#Id
#GeneratedValue
#Column(nullable = false, updatable = false)
protected Long id;
#Transient
private Long tempId;
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
private void setTempId(Long tempId) {
this.tempId = tempId;
}
// Fix Id on first call from equal() or hashCode()
private Long getTempId() {
if (tempId == null)
// if we have id already, use it, else use 0
setTempId(getId() == null ? 0 : getId());
return tempId;
}
#Override
public boolean equals(Object obj) {
if (super.equals(obj))
return true;
// take proxied object into account
if (obj == null || !Hibernate.getClass(obj).equals(this.getClass()))
return false;
Entity o = (Entity) obj;
return getTempId() != 0 && o.getTempId() != 0 && getTempId().equals(o.getTempId());
}
// hash doesn't change in time
#Override
public int hashCode() {
return getTempId() == 0 ? super.hashCode() : getTempId().hashCode();
}
}
IMO you have 3 options for implementing equals/hashCode
Use an application generated identity i.e. a UUID
Implement it based on a business key
Implement it based on the primary key
Using an application generated identity is the easiest approach, but comes with a few downsides
Joins are slower when using it as PK because 128 Bit is simply bigger than 32 or 64 Bit
"Debugging is harder" because checking with your own eyes wether some data is correct is pretty hard
If you can work with these downsides, just use this approach.
To overcome the join issue one could be using the UUID as natural key and a sequence value as primary key, but then you might still run into the equals/hashCode implementation problems in compositional child entities that have embedded ids since you will want to join based on the primary key. Using the natural key in child entities id and the primary key for referring to the parent is a good compromise.
#Entity class Parent {
#Id #GeneratedValue Long id;
#NaturalId UUID uuid;
#OneToMany(mappedBy = "parent") Set<Child> children;
// equals/hashCode based on uuid
}
#Entity class Child {
#EmbeddedId ChildId id;
#ManyToOne Parent parent;
#Embeddable class ChildId {
UUID parentUuid;
UUID childUuid;
// equals/hashCode based on parentUuid and childUuid
}
// equals/hashCode based on id
}
IMO this is the cleanest approach as it will avoid all downsides and at the same time provide you a value(the UUID) that you can share with external systems without exposing system internals.
Implement it based on a business key if you can expect that from a user is a nice idea, but comes with a few downsides as well
Most of the time this business key will be some kind of code that the user provides and less often a composite of multiple attributes.
Joins are slower because joining based on variable length text is simply slow. Some DBMS might even have problems creating an index if the key exceeds a certain length.
In my experience, business keys tend to change which will require cascading updates to objects referring to it. This is impossible if external systems refer to it
IMO you shouldn't implement or work with a business key exclusively. It's a nice add-on i.e. users can quickly search by that business key, but the system shouldn't rely on it for operating.
Implement it based on the primary key has it's problems, but maybe it's not such a big deal
If you need to expose ids to external system, use the UUID approach I suggested. If you don't, you could still use the UUID approach but you don't have to.
The problem of using a DBMS generated id in equals/hashCode stems from the fact that the object might have been added to hash based collections before assigning the id.
The obvious way to get around this is to simply not add the object to hash based collections before assigning the id. I understand that this is not always possible because you might want deduplication before assigning the id already. To still be able to use the hash based collections, you simply have to rebuild the collections after assigning the id.
You could do something like this:
#Entity class Parent {
#Id #GeneratedValue Long id;
#OneToMany(mappedBy = "parent") Set<Child> children;
// equals/hashCode based on id
}
#Entity class Child {
#EmbeddedId ChildId id;
#ManyToOne Parent parent;
#PrePersist void postPersist() {
parent.children.remove(this);
}
#PostPersist void postPersist() {
parent.children.add(this);
}
#Embeddable class ChildId {
Long parentId;
#GeneratedValue Long childId;
// equals/hashCode based on parentId and childId
}
// equals/hashCode based on id
}
I haven't tested the exact approach myself, so I'm not sure how changing collections in pre- and post-persist events works but the idea is:
Temporarily Remove the object from hash based collections
Persist it
Re-add the object to the hash based collections
Another way of solving this is to simply rebuild all your hash based models after an update/persist.
In the end, it's up to you. I personally use the sequence based approach most of the time and only use the UUID approach if I need to expose an identifier to external systems.
I tried to answer this question myself and was never totally happy with found solutions until i read this post and especially DREW one. I liked the way he lazy created UUID and optimally stored it.
But I wanted to add even more flexibility, ie lazy create UUID ONLY when hashCode()/equals() is accessed before first persistence of the entity with each solution's advantages :
equals() means "object refers to the same logical entity"
use database ID as much as possible because why would I do the work twice (performance concern)
prevent problem while accessing hashCode()/equals() on not yet persisted entity and keep the same behaviour after it is indeed persisted
I would really apreciate feedback on my mixed-solution below
public class MyEntity {
#Id()
#Column(name = "ID", length = 20, nullable = false, unique = true)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id = null;
#Transient private UUID uuid = null;
#Column(name = "UUID_MOST", nullable = true, unique = false, updatable = false)
private Long uuidMostSignificantBits = null;
#Column(name = "UUID_LEAST", nullable = true, unique = false, updatable = false)
private Long uuidLeastSignificantBits = null;
#Override
public final int hashCode() {
return this.getUuid().hashCode();
}
#Override
public final boolean equals(Object toBeCompared) {
if(this == toBeCompared) {
return true;
}
if(toBeCompared == null) {
return false;
}
if(!this.getClass().isInstance(toBeCompared)) {
return false;
}
return this.getUuid().equals(((MyEntity)toBeCompared).getUuid());
}
public final UUID getUuid() {
// UUID already accessed on this physical object
if(this.uuid != null) {
return this.uuid;
}
// UUID one day generated on this entity before it was persisted
if(this.uuidMostSignificantBits != null) {
this.uuid = new UUID(this.uuidMostSignificantBits, this.uuidLeastSignificantBits);
// UUID never generated on this entity before it was persisted
} else if(this.getId() != null) {
this.uuid = new UUID(this.getId(), this.getId());
// UUID never accessed on this not yet persisted entity
} else {
this.setUuid(UUID.randomUUID());
}
return this.uuid;
}
private void setUuid(UUID uuid) {
if(uuid == null) {
return;
}
// For the one hypothetical case where generated UUID could colude with UUID build from IDs
if(uuid.getMostSignificantBits() == uuid.getLeastSignificantBits()) {
throw new Exception("UUID: " + this.getUuid() + " format is only for internal use");
}
this.uuidMostSignificantBits = uuid.getMostSignificantBits();
this.uuidLeastSignificantBits = uuid.getLeastSignificantBits();
this.uuid = uuid;
}
This is a common problem in every IT system that uses Java and JPA. The pain point extends beyond implementing equals() and hashCode(), it affects how an organization refer to an entity and how its clients refer to the same entity. I've seen enough pain of not having a business key to the point that I wrote my own blog to express my view.
In short: use a short, human readable, sequential ID with meaningful prefixes as business key that's generated without any dependency on any storage other than RAM. Twitter's Snowflake is a very good example.
I using a class EntityBase and inherited to all my entities of JPA and this it works very good to me.
/**
* #author marcos.oliveira
*/
#MappedSuperclass
public abstract class EntityBase<TId extends Serializable> implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id", unique = true, nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
protected TId id;
public TId getId() {
return this.id;
}
public void setId(TId id) {
this.id = id;
}
#Override
public int hashCode() {
return (super.hashCode() * 907) + Objects.hashCode(getId());//this.getId().hashCode();
}
#Override
public String toString() {
return super.toString() + " [Id=" + id + "]";
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
EntityBase entity = (EntityBase) obj;
if (entity.id == null || id == null) {
return false;
}
return Objects.equals(id, entity.id);
}
}
Reference: https://thorben-janssen.com/ultimate-guide-to-implementing-equals-and-hashcode-with-hibernate/
If UUID is the answer for many people, why don't we just use factory methods from business layer to create the entities and assign primary key at creation time?
for example:
#ManagedBean
public class MyCarFacade {
public Car createCar(){
Car car = new Car();
em.persist(car);
return car;
}
}
this way we would get a default primary key for the entity from the persistence provider, and our hashCode() and equals() functions could rely on that.
We could also declare the Car's constructors protected and then use reflection in our business method to access them. This way developers would not be intent on instantiate Car with new, but through factory method.
How'bout that?
In practice it seems, that Option 2 (Primary key) is most frequently used.
Natural and IMMUTABLE business key is seldom thing, creating and supporting synthetic keys are too heavy to solve situations, which are probably never happened.
Have a look at spring-data-jpa AbstractPersistable implementation (the only thing: for Hibernate implementation use Hibernate.getClass).
public boolean equals(Object obj) {
if (null == obj) {
return false;
}
if (this == obj) {
return true;
}
if (!getClass().equals(ClassUtils.getUserClass(obj))) {
return false;
}
AbstractPersistable<?> that = (AbstractPersistable<?>) obj;
return null == this.getId() ? false : this.getId().equals(that.getId());
}
#Override
public int hashCode() {
int hashCode = 17;
hashCode += null == getId() ? 0 : getId().hashCode() * 31;
return hashCode;
}
Just aware of manipulating new objects in HashSet/HashMap.
In opposite, the Option 1 (remain Object implementation) is broken just after merge, that is very common situation.
If you have no business key and have a REAL needs to manipulate new entity in hash structure, override hashCode to constant, as below Vlad Mihalcea was advised.
Below is a simple (and tested) solution for Scala.
Note that this solution does not fit into any of the 3 categories
given in the question.
All my Entities are subclasses of the UUIDEntity so I follow the
don't-repeat-yourself (DRY) principle.
If needed the UUID generation can be made more precise (by using more
pseudo-random numbers).
Scala Code:
import javax.persistence._
import scala.util.Random
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
abstract class UUIDEntity {
#Id #GeneratedValue(strategy = GenerationType.TABLE)
var id:java.lang.Long=null
var uuid:java.lang.Long=Random.nextLong()
override def equals(o:Any):Boolean=
o match{
case o : UUIDEntity => o.uuid==uuid
case _ => false
}
override def hashCode() = uuid.hashCode()
}

Elegant way to assign object id in Java

I have a class for objects ... lat's say apples.
Each apple object mush have a unique identifier (id)... how do I ensure (elegantly and efficiently) that newly created has unique id.
Thanks
have a static int nextId in your Apple class and increment it in your constructor.
It would probably be prudent to ensure that your incrementing code is atomic, so you can do something like this (using AtomicInteger). This will guarantee that if two objects are created at exactly the same time, they do not share the same Id.
public class Apple {
static AtomicInteger nextId = new AtomicInteger();
private int id;
public Apple() {
id = nextId.incrementAndGet();
}
}
Use java.util.UUID.randomUUID()
It is not int, but it is guaranteed to be unique:
A class that represents an immutable universally unique identifier (UUID).
If your objects are somehow managed (for example by some persistence mechanism), it is often the case that the manager generates the IDs - taking the next id from the database, for example.
Related: Jeff Atwood's article on GUIDs (UUIDs). It is database-related, though, but it's not clear from your question whether you want your objects to be persisted or not.
Have you thought about using UUID class. You can call the randomUUID() function to create a new id everytime.
There is another way to get unique ID's. Instead of using an int or other data type, just make a class:
final class ID
{
#Override
public boolean equals(Object o)
{
return this==o;
}
}
public Apple
{
final private ID id=new ID();
}
Thread safe without synchronizing!

Categories