Showing posts with label annotations. Show all posts
Showing posts with label annotations. Show all posts

Thursday, 10 July 2025

@Nonnull versus @NotNull

A quick small blog...

So, we have two (seemingly) conflicting annotations for the same thing1.

Even people who know exactly when to use what have a chance to pick the wrong one, especially with the use of Code Completion and AI nowadays.

So here's a quick rundown, but the reference below is much more in depth:

import javax.annotation.Nonnull;

@Nonnull
IDEs and Compilers use it for Static Analysis of code. (Though the RetentionPolicy is set to RUNTIME)
import jakarta.validation.constraints.NotNull;

@NotNull
Validation Frameworks (like ORMs) use it during Runtime for checks.

What about Nullable values?

import javax.annotation.Nullable;

@Nullable
IDEs and Compilers use it for Static Analysis of code.

There is no @Nullable available for jakarta.validation.constraints. By default things are nullable, unless explicitly mentioned otherwise.

When not to use @NotNull

The primary really important thing to take away from this is to not do the following:

It might work, your IDE might complain or it might not, but at runtime this will be ignored, unless this method is called by a Framework as mentioned above.

Addendum

Don't use javax.validation.constraints.NotNull. It's been superseded by Jakarta when Oracle moved Java EE to Jakarta. See [2].

Referenties

[1] Medium - Understanding @NotNull vs @Nonnull in Java: A Practical Guide to Null-Safety
https://medium.com/@mesfandiari77/understanding-notnull-vs-nonnull-in-java-a-practical-guide-to-null-safety-5e179e918f37
[2] Medium - Difference between javax.validation and jakarta.validation
https://medium.com/@ovinduuu/difference-between-javax-validation-and-jakarta-validation-df0c6dbe5cb3

Thursday, 29 March 2018

Modelling Java Annotations in UML

I was wondering how to put Java Annotations in an UML schema.

Turns out there is no support for it, but some smart people gave it a try anyway and wrote it down in a paper1. Of course they are using the already existing possibilities of UML, so the UML does not exactly match up with the idea of Annotations.

Annotations can be applied to declarations: declarations of classes, fields, methods, and other program elements. Since Java 8, also annotations are supported anywhere a type is used2.

However, some people3 do have a valid point when they say that modelling Annotations might be a severe case of micromodelling.

PlantUML

It's not a secret that I am a fan of plantuml4, and all the pretty pictures on this page are dynamically created by the PlantUML Online Server5 that they have running. Which also means, if the pictures are not visible, the server is down.

I wanted to see how far I could take PlantUML in processing the ideas in the paper.

1. Attributes as UML Stereotypes

@startuml
class  Mail <<@FunctionalInterface>> <<@Table(name = "mm_mailtable")>> {
  -@Id id: Long
  -@NotNull @Column subject: String
  +getId(): Long
  +setId(id: Long)
}
@enduml

2. Attributes as extra class subbox

@startuml
class Mail {
  @Entity
  @Table(name = "mm_mailtable")
  --
  -@NotNull @Column subject: String
  --
  +getId(): Long
  +setId(id: Long)
}
@enduml

3. Attributes as UML Template Parameter

@startuml
class Mail <@Entity \n @Table(name = "mm_mailtable")> {
  -@Id id: Long
  -@NotNull @Column subject: String
  --
  +getId(): Long
  +setId(id: Long)
}
@enduml

4. Attributes as separate Class

@startuml
class Mail {
  -@Id id: Long
  -@NotNull @Column subject: String
  --
  +getId(): Long
  +setId(id: Long)
}
class "@Entity \n @Table(name = "mm_mailtable")" as Entity
Entity - Mail : <<annotated>>
@enduml

5. Attributes as Comment boxes

@startuml
class Mail {
  -@Id id: Long
  -@NotNull @Column subject: String
  --
  +getId(): Long
  +setId(id: Long)
}
note right
@Entity
@Table(name = "mm_mailtable")
end note
@enduml

Conclusion

My personal opinion is that UML Stereotypes folllows the Java class most narrowly, so I like that. But I think the "Annotations as a separate class" follows UML conventions quite good.

The paper contains a nice table where they are considering the pros and cons of all the methods described above.

As there seems no standard defined in UML, if you need to model Annotations at all (and that's a big if), pick the one you like.

References

[1] Representing Explicit Attributes in UML
http://dawis2.icb.uni-due.de/events/AOM_MODELS2005/Cepa.pdf
[2] Oracle Tutorial - Annotations
https://docs.oracle.com/javase/tutorial/java/annotations/basics.html
[3] CodeRanch - UML / Class Diagram Syntax for Java Annotations
https://coderanch.com/t/100641/UML-Class-Diagram-Syntax-Java
[4] Plantuml
http://plantuml.com/
[5] Plantuml Online Server
http://www.plantuml.com/plantuml/uml/SyfFKj2rKt3CoKnELR1Io4ZDoSa70000
GitHUb - Mail.java
https://github.com/maartenl/Land-of-Karchan/blob/master/karchangame/src/main/java/mmud/database/entities/game/Mail.java

Thursday, 23 November 2017

@SuppressWarnings

I accidentally stumbled upon a blogpost showing all available SuppressWarnings values1. Convenient.

References

[1] all that jazz - List of SuppressWarnings arguments
https://jazzy.id.au/2008/10/30/list_of_suppresswarnings_arguments.html

Thursday, 13 August 2015

@VisibleForTesting

I recently encountered the following annotation in the source code at work:
@VisibleForTesting
It is one I had not seen before. Below is an example of what it looked like.
@VisibleForTesting
void updateTaxation(TaxationData data) 
{
    ...
}
The annotation is part of the com.google.common.annotations package.

It turns out that it is a Marker annotation, simply to communicate to (other) software designers that the access level modifier has been relaxed, to make the code more easy to test.

In the example above, the access level modifier is "default", while it should/could have been "private".

I am still not convinced this is a good thing, because you changed production code to fix a testing problem.

We could work around this issue by using Reflection to access private methods/members, but Reflection is very brittle, especially when dealing with living code. So, that doesn't appeal to me either.

The best way, is to either:
  • test the private method, by using the public api that uses it
  • if this not enough, you can move the private method into a Strategy object1, and test the Strategy object in isolation

References

[1] Wikipedia - Strategy Pattern
https://en.wikipedia.org/wiki/Strategy_pattern
[2] StackOverflow -annotation to make a private method public only for test classes
http://stackoverflow.com/questions/6913325/annotation-to-make-a-private-method-public-only-for-test-classes

Sunday, 16 February 2014

package.html vs. package-info.java

Found a good reference1 on why you should use a package-info.java class.

Notes:
  • can contain (package) annotations
  • package-info is not a legal identifier for a class2. So there's no chance of mistakes from the compiler.
  • “It is recommended that package-info.java, if it is present, take the place of package.html for javadoc and other similar documentation generation systems.”2
  • you're not messing up your source files with .html files, which was in fact the case with the old package.html.

References

[1] Javadoc: package.html or package-info.java
http://stackoverflow.com/questions/3644726/javadoc-package-html-or-package-info-java
[2] The Java™ Language Specification - Java SE 7
http://docs.oracle.com/javase/specs/

Sunday, 8 December 2013

JSR 305: Annotations for Software Defect Detection

The NullPointerException is the most prevalent exception thrown in Java programs known to man. Dealing with it has always caused a great deal of Null checks in my (and other peoples) code.

At work we've recently started using the special annotations from JSR 305[1].

There are basically two. Nullable to indicate that a result of variable can be Null, and Nonnull to indicate that a result or variable will never be null.

The JSR 305 annotations are primarily intended for compilers or other tools that read source code. However, they are usually retained in the byte code for the benefit of static analysis tools such as FindBugs that inspect byte code rather than source.

An added benefit is that it forces me to think about what a method should return.

Eclipse, our work environment, has its own versions of those annotations, which we do not use.
  • org.eclipse.jdt.annotation.Nullable
  • org.eclipse.jdt.annotation.NonNull
  • org.eclipse.jdt.annotation.NonNullByDefault

The originals from JSR 305[1] are:
  • javax.annotation.Nullable
  • javax.annotation.Nonnull
  • javax.annotation.ParametersAreNonnullByDefault

In order to get the proper annotations, we do have to include a jar file. We use "jsr305-2.0.1.jar".

At the start of using these annotations, I've turned "Errors" off, regarding the Null annotations, as I was getting far too many errors.

The Executive Committee voted to list this JSR as dormant in May 2012. But the implementation of JSR 305 [1] seems to work in several IDEs.

Eclipse problems and workarounds

The tooling in Eclipse is of course not perfect in detecting where a Null is a possible problem. There are ways to help Eclipse make the right decision. In the examples below, the part of the code that Eclipse will indicate as being faulty is red underlined.
  1. The following code shows up Faulty in Eclipse. Eclipse/FindBugs cannot determine that the check for null negates the second possible NullPointer.
    // Potential null pointer access: The method getItem() may return null
    if (order.getItem() == null
    {
        logger.debug("order has no item.");
        continue;
    }
    int price = compute(order.getItem());
    The workaround is as easy as making a temporary local variable.
    // no problem!
    Item item = order.getItem();
    if (item == null
    {
        logger.debug("order has no more items.");
        continue;
    }
    int price = compute(item);
  2. Warning in the second line. Eclipse is not clever enough to figure out that assertNotNull will take care of it. Eclipse is smart, but not psychic.
    assertNotNull(order.getItem());
    assertNotNull(order.getItem().getDescription());
    Replace it with another local variable and put some supressors on it.
    assertNotNull(order.getItem());
    @SuppressWarnings("null")
    @Nonnull
    Item item = order.getItem();
    assertNotNull(item.getDescription());
  3. NullChecks are not being used in the original Java API, causing potential warnings. In the example, without the SuppressWarnings on the method, the last return would be underlined.
    @SuppressWarnings("null")
    public @Nonnull Set<Item> getItems() 
    {
        if (items == null
        {
            return Collections.emptySet();
        }
        return Collections.unmodifiableSet(items);
    }
  4. I've encountered an issue with Enums. Why does this happen? I have no clue.
       boolean result = hasProperty(name, StateEnum.MANDATORY);
       return result;
    }

    private boolean hasProperty(@Nullable String name, @Nonnull StateEnum state)
    {
       ....
    I can solve it in the obvious way, but am unable to find the cause of the problem.
       @SuppressWarnings("null")
       boolean result = hasProperty(name, StateEnum.MANDATORY);
       return result;
    }

    private boolean hasProperty(@Nullable String name, @Nonnull StateEnum state)
    {
       ....
  5. If the Null constraint annotations are not used in the Interface (specifically method parameters... it seems method return values don't matter), you are not allowed to add them in your implementation. You will receive the error message from eclipse.
    Multiple markers at this line
    - Illegal redefinition of parameter myParam, inherited method from SomeInterface does not constrain this parameter
    - implements mrbear.some.SomeInterfaceImpl.myMethod
  6. You are better off not using @Nonnull at the Hibernate Entity Level, as that is going to cause problems in some cases. Notable when using "Examples" for searching.

Note: Of course, it is a code smell to have to change your production code, to help Eclipse tooling deal with Null. This is probably the main reason, why it doesn't have the expected uptake in my company.

Mushroom cloud


Changing your existing code base to make use of this new check, is quite a job. If you start at a specific point (the point, to be more specific, where you were changing your code initially), it tends to mushroom cloud outwards. Somewhere along the line, you have to decide how far you wish to take this.

It would have been a great deal simpler, to have added this functionality straight from the beginning. Alas, hindsight is always 20-20.

Frameworks


I've not discovered any frameworks that inherently are using the same JSR305, except for one. Google Guava.

Generics


Recently had the issue that I had a List, of which I knew that each member of that List was not NULL. But I had no way of annotating this with @Nonnull.

It appears it is possible to (among other things) annotate generics once JSR 308[3] is added to Java. It is scheduled for Java 8 for now.[4]

The Checker Framework[2] makes it possible right now, apparently.

The syntax would look something like this:
protected @Nonnull List<@Nonnull String> getNames() {

Updated: 10/12/2013 added chapter on Generics and a problem-case I encountered.

Updated: 20/02/2014 added a critical note at the end of the chapter of "Eclipse problems and workarounds".

References

[1] JSR 305: Annotations for Software Defect Detection
http://jcp.org/en/jsr/detail?id=305
Avoiding “!= null” statements in Java?
http://stackoverflow.com/questions/271526/avoiding-null-statements-in-java
The Open Road: javax.annotation.
https://today.java.net/pub/a/today/2008/09/11/jsr-305-annotations.html
[2] Checker Framework
http://types.cs.washington.edu/checker-framework/
[3] JSR 308: Annotations on Java Types
http://jcp.org/en/jsr/detail?id=308
[4] JSR 337: JavaTM SE 8 Release Contents
http://jcp.org/en/jsr/detail?id=337

Tuesday, 16 July 2013

Formula

The Formula annotation is used on a property of a Hibernate entity. It is currently not a part of the Java Persistence Standard, and thusly is a Hibernate extension.

I thought I'd write some of my notes and bookmarks to other sites here, as the information in the Hibernate book seems very brief.


Advantages

  • the SQL in the formula is inserted automatically whenever you retrieve the Entity, without you having to think about it.
  • the advantage compared to calculating the fields in the Getter or Setter, is that it is possible to use the property in HQL queries. For example, adding "ORDER BY existsFreeby" in HQL without problems.

Disadvantages

  • HQL cannot be used in the Formula.
  • you have plain SQL in your Entity. I know this is normal according to the JPA spec, but at work they tend to frown on that. Don't ask me why.
  • whenever a keyword is unknown, it will prefix it with the name of the Entity table. This is a good feature, normally. In the example give, for example, the "id" will be expanded to "ORDERS0_.id". However, in the case where we used COALESCE, if we had a space between COALESCE and the opening bracket, like so "COALESCE (", Hibernate would expand this to "ORDERS0_.COALESCE (" causing an error, obviously.
  • a problem can occur when you are using ansi sql queries and using query.addEntity(Orders.class); It will break on that now.

Note

Always use opening and closing brackets at the beginning and end of the actual SQL part. As it is inserted into the Hibernate created SQL, it might break the syntax if you forget.

References

2.4.3.1. Formula
http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/
Hibernate derived properties
http://blog.eyallupu.com/2009/07/hibernate-derived-properties.html
Calculated property with JPA / Hibernate
http://stackoverflow.com/questions/2986318/calculated-property-with-jpa-hibernate
@Formula adds a this_. prefix to an SQL function - Hibernate HH-5265
https://hibernate.atlassian.net/browse/HHH-5265
Hibernate with JPA ignoring @Formula
http://stackoverflow.com/questions/7824805/hibernate-with-jpa-ignoring-formula

Sunday, 9 October 2011

Different Ways to use JPQL

Introduction

There are several ways in which to execute JPQL (Java Persistence Query Language). I'll introduce the "old way" first, with JDBC and direct connections to the database, before branching off into the ways used by ORMs (Object Relational Mapping).

Each way has its advantages and disadvantages.

The old way:
  • direct database access
  • database connection pool
Using an ORM
  • hql in java code
  • named queries in annotations
  • named queries in xml
  • Criterion API
  • retrieving the object by its primary key

The Old Way

Direct Database Access

This is an example of direct database connection with jdbc. Setting it up, sending the query, reading the result, close the resultset and shutting down the connection.


/**
 * Connects to the database using an url. The url looks something like
 * "jdbc:mysql://localhost.localdomain/mud?user=root&password=". Uses the
 * classname in Constants.dbjdbcclass to get the right class for interfacing
 * with the database server. If the database used is changed (or to be more
 * specific the jdbc driver is changed) change the constant.
 * 
 * @throws InstantiationException
 *             happens when it is impossible to instantiate the proper
 *             database class, from the class name as provided by
 *             Constants.dbjdbcclass.
 * @throws ClassNotFoundException
 *             happens when it is impossible to find the proper database
 *             class, from the class name as provided by
 *             Constants.dbjdbcclass.
 * @throws IllegalAccessException
 *             happens when it is not possible to create the database class
 *             because access restrictions apply.
 * @throws SQLException
 *             happens when a connection to the database Server could not be
 *             established.
 */

public Macro runQuery() throws SQLException, InstantiationException,
    ClassNotFoundException, IllegalAccessException
{
  Macro result = null;
  try
  {
    Class.forName(Constants.dbjdbcclass).newInstance();

    // jdbc:mysql://[host][,failoverhost...][:port]/[database]
    // [?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]...
    String theUrl = Constants.dburl + "://" + Constants.dbhost
      + Constants.dbdomain + "/" + Constants.dbname + "?user="
      + Constants.dbuser + "&password=" + Constants.dbpasswd;
    theConnection = DriverManager.getConnection(theUrl);

    PreparedStatement statGetMacro = null;
    statGetMacro = theConnection.prepareStatement(sqlGetMacro);
    statGetMacro.setString(2, macroname);
    res = statGetMacro.executeQuery();
    if (res != null && res.next())
    {
      result = new Macro(res.getString("macroname"), res.getString("contents"));
      res.close();
    }
    statGetMacro.close();
  } catch (Exception e)
  {
    throw new MudDatabaseException(Constants.DATABASECONNECTIONERROR, e2);
  }
  finally
  {
    if (theConnection != null) {theConnection.close();}
  }
  return result;
}
Advantages:
  • complete control
  • very little libraries required
Disadvantages:
  • sql syntax spread throughout the java code
  • lots of error-prone boiler plate code required
  • expensive in setting up new database connections for every query
  • sytax of query not checked, until method called
  • changing the query requires source code change, recompilation, repackaging, etc

Database Connection Pool

This is example of database connection with jndi resource pool, where the only thing required is the jndi name. In this case it is irrelevant which connection we receive from the connection pool. The actual theConnection.close() does nothing, but returns the connection back to the pool.


public void runQuery() throws Exception
{
  Connection con=null;
  ResultSet rst=null;
  PreparedStatement stmt=null;

  try
  {
    Context ctx = new InitialContext();
    DataSource ds = (DataSource) ctx.lookup("jdbc/mmud");
    con = ds.getConnection();

    stmt=con.prepareStatement("select * from links where type = 1 order by creation");
    rst=stmt.executeQuery();
    while(rst.next())
    {
        out.println("<li><A HREF=\"" + rst.getString("url") + "\">" +
          rst.getString("linkname") + "</A> (<i>" +
          rst.getString("name") + "</i>)<P>");
    }
    rst.close();
    stmt.close();
  }        
  finally
  {
    if (rst != null) {try {rst.close();} catch (Exception e){}}
    if (stmt != null) {try {stmt.close();} catch (Exception e)}}
    if (con != null) {try {con.close();} catch (Exception e){}}
  }
}

Advantages:
  • database connection resource pool
  • no need to open and close connection, connections are reused
Disadvantages:
  • sql syntax spread throughout the java code
  • still a lot of error-prone boiler plate code required
  • sytax of query not checked, until method called
  • if connections/resources not properly released, the pool will run out of connections/resources
  • changing the query requires source code change, recompilation, repackaging, etc

Using an ORM

hql in java code

@Override
public void deleteAddress() 
{
  StringBuilder queryBuilder = new StringBuilder();
  queryBuilder.append("DELETE Address address ");
  queryBuilder.append("WHERE  address.country = 'Italy' ");
  queryBuilder.append("AND NOT EXISTS (SELECT '' ");
  queryBuilder.append("            FROM Customer cust ");
  queryBuilder.append("            WHERE cust.address = address ");
  queryBuilder.append("           ) ");

  Query query = em.createQuery(queryBuilder.toString());
  query.executeUpdate();
}

Unfortunately, the code above is what I encounter frequently in the source of my employers current software product.

Advantages:
  • none
Disadvantages:
  • a StringBuffer is created every time the method is called, at the very least this should be a constant
  • jpql is created and parsed and compiled every time the method is called
  • sql/hql/jpql syntax spread throughout the java code
  • sytax of query not checked, until method called
  • changing the query requires source code change, recompilation, repackaging, etc


Named queries in annotations

Queries can be defined in the annotations on top of Entity classes. The annotation would look a little like the one below.

@NamedQueries({
    @NamedQuery(name = "Character.findAll", query = "SELECT c FROM Character c"),
    @NamedQuery(name = "Character.findByName", query = "SELECT c FROM Character c WHERE c.name = :name")})

One of the problems often heard is that the annotation has to be on an Entity class, when you perhaps would prefer to have it someplace else. In that case, it might be an idea to define the constants as strings in a different part, like a Service or a DAO or what have you, and refer to them in the NamedQuery annotations. Like in the two-part example below.

As the name of a named query is global within the persistent provider, it is essential to create unique names within the application. That is why in most cases, the name of a named query is prefixed with the class name.

/**
 * Game bean.
 * @author Mr. Bear
 */

@Stateless
@Remote(GameBeanRemote.class)
public class GameBean implements GameBeanRemote
{
    public static final String character = "Character";

    /**
     * label for the find all characters query.
     */

    public static final String FINDALLCHARS_QUERYNAME = character + ".findAll";

    /**
     * query for the find of all characters query.
     */

    public static final String FINDALLCHARS_QUERY = "SELECT c FROM Character c";

    /**
     * label for the find character based on name query.
     */

    public static final String FINDCHAR_QUERYNAME = character + ".findByName";

    /**
     * query for the find of character based on name query.
     */

    public static final String FINDCHAR_QUERY = "SELECT c FROM Character c WHERE c.name = :name";

    @PersistenceContext(unitName = "datasource")
    private EntityManager em;
/**
 * The Character entity.
 * @author Mr. Bear
 */

@Entity
@Table(name = "mm_usertable")
@NamedQueries({
   @NamedQuery(name = GameBean.FINDALLCHARS_QUERYNAME, query = GameBean.FINDALLCHARS_QUERY),
   @NamedQuery(name = GameBean.FINDCHAR_QUERYNAME, query = GameBean.FINDCHAR_QUERY)})
public class Character implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 20)
    @Column(name = "name")
    private String name;

Using the named queries in code is as simple as getting the entity manager and telling him the name of the NamedQuery you wish to use, add the parameter values, and request the result. You can refer to the NamedQueries by name, hence the name, get it?

@Override
public CommandOutput retrieveCharacter(String name)
{
    itsLog.entering(this.getClass().getName(), "retrieveCharacter");
    Query q = em.createNamedQuery("Character.findByName", Character.class);
    q.setParameter("name", name);
    Character c = (Character) q.getSingleResult();
    if (c == null)
    {
        itsLog.exiting(this.getClass().getName(), "retrieveCharacter");
        return new CommandOutput("""""");
    }
    CommandOutput co = new CommandOutput(c.getName(), c.getArm(), c.getBeard());
    itsLog.exiting(this.getClass().getName(), "retrieveCharacter ", co);
    return co;
}

The great part of NamedQueries is that they are checked and pre-compiled by Hibernate when the server starts, so you get instant messages if you screwed up the syntax.

Advantages:
  • the Persistence provider might be able to precompile them, and this can help catch bugs before deployment
  • sql syntax no longer spread throughout the java code
  • sql queries externalised to the java code
  • there's a central place for queries, making them easy to find and easy to re-use.
Disadvantages:
  • named queries in annotations can only be added to the Entity classes or the SuperMapClass. This is especially awkward when you have a query spanning multiple entities.
  • named queries are referenced using a key, which is global to the application.
  • named queries are a little difficult to debug, as a change requires an application server reboot.
  • changing the query in the annotation requires source code change, recompilation, repackaging, etc

In the examples below, JBoss is used in combination with Hibernate. The first example is the jboss log when things go wrong, and the second example is when things go right.

09:19:23,635 ERROR [SessionFactoryImpl] Error in named query: FullAddress.findAddressesOfCustomers
org.hibernate.QueryException: could not resolve property: entitynr of: mrbear.entity.Address [DELETE Address address WHERE address.country = 'Italy' AND address.entitynr > 1000 AND NOT EXISTS (SELECT '' FROM Customer cust WHERE cust.address = address) ]
at org.hibernate.persister.entity.AbstractPropertyMapping.propertyException(AbstractPropertyMapping.java:67)
09:23:10,946 INFO [AnnotationBinder] Binding entity from annotated class: mrbear.entity.Address
09:23:10,948 INFO [QueryBinder] Binding Named query: FullAddress.findAddressesOfCustomers => DELETE Address address WHERE address.country = 'Italy' AND address.entityNr > 1000 AND NOT EXISTS (SELECT '' FROM Customer cust WHERE cust.address = address)

Let me point you especially to the fact that HQL (or JPQL for that matter), contrary to SQL, is case-sensitive (for the most part). It would have to be, as it has a direct link to java classes and these are also case-sensitive.

In the example above, the getter and setter for entity number was specified as getEntityNr and setEntityNr, hence the problem with the casing in the first example.

According to Gavin King [1]:
We leave it up to you if you want to utilize the named query feature. However, we consider query strings in the application code (except if they're in annotations) to be the second choice; you should always externalize query strings if possible.

Named queries in xml

If you do not like to have your JPQL in your code at all, there is always the possibility of putting the queries into the xml files that are a part of the configuration of the jar file.

There is no reason why you cannot have both, both named queries in your annotations and queries in your xml persistence configuration files.

One of the great things is that the named queries in the persistence xml files take precedence over the named queries in the annotations. This means, that, when deployed in a specific production environment, it is possible to change the named queries, without having to touch/recompile/build/package the java source code. So, you can do convention over configuration.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="mmud" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>mmud</jta-data-source>
    <!-- Named JPQL queries per entity, but any other organization is possible  -->
    <mapping-file>META-INF/jpql/Character.xml</mapping-file>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties/>
  </persistence-unit>
</persistence>
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="1.0" xmlns="http://java.sun.com/xml/ns/persistence/orm"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd "
>

    <named-query name="Character.findByName">
        <query>
            SELECT
                c
            FROM
                Character c
            WHERE
                c.password = :name
            OR
                c.name = 'Midevia'
        </query>
    </named-query>
</entity-mappings>

So in the code example that uses annotations, when using these two persistence xml files displayed above, suddenly "Midevia" is retrieved from the database, instead of the name you requested.

Advantages:
  • the Persistence provider might be able to precompile them, and this can help catch bugs before deployment
  • sql syntax no longer anywhere in the java code
  • there's a central place for queries, making them easy to find and easy to re-use.
  • named queries can be spread through many different xml files, making them more easy to categorise.
Disadvantages:
  • named queries are referenced using a key, which is global to the application.
  • named queries in xml, can be changed, if you don't mind hacking your way through xml.
  • named queries are a little difficult to debug, as a change requires an application server reboot.

Criterion API

@Override
public CommandOutput retrieveCharacter(String name)
{
    itsLog.entering(this.getClass().getName(), "retrieveCharacter");

    // setup criteria builders/queries
    CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
    CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();

    // add from
    Root<Character> from = criteriaQuery.from(Character.class);
    CriteriaQuery<Character> select = criteriaQuery.select(from);

    // add predicate
    Predicate predicate = criteriaBuilder.equal(from.get("name"), name);
    criteriaQuery.where(predicate);

    // create the select query
    TypedQuery<Character> typedQuery = em.createQuery(select);

    // get the results
    List<Character> resultList = typedQuery.getResultList();

    if (resultList == null || resultList.size() != 1)
    {
       itsLog.exiting(this.getClass().getName(), "retrieveCharacter");
       return new CommandOutput("""""");
    }
    CommandOutput co = new CommandOutput(
            resultList.get(0).getName(),
            resultList.get(0).getArm(),
            resultList.get(0).getBeard());
    itsLog.exiting(this.getClass().getName(), "retrieveCharacter ", co);
    return co;
}
Advantages:
  • the Persistence provider might be able to precompile them, and this can help catch bugs before deployment
  • sql syntax no longer anywhere in the java code
  • the query is dynamic, making it easy to change depending on input from the user
  • it is java, so every tool and compiler can aid in the development, like syntax checking and type checking and the like
Disadvantages:
  • fairly unreadable

Retrieving the object by its primary key

Ideally, we do not wish to use SQL or HQL or the Criteria API at all. If possible, we just want to tell the Entity Manager to get the objects we need. In most cases, this is not easy. But for some concepts, like getting an object based on its primary key (so we are always sure there's just one (or zero) available) there's a much more straightforward way.

@Override
public CommandOutput retrieveCharacter(String name)
{
    itsLog.entering(this.getClass().getName(), "retrieveCharacter");
    Character c = em.find(Character.class, name);
    if (c == null)
    {
        itsLog.exiting(this.getClass().getName(), "retrieveCharacter");
        return new CommandOutput("""""");
    }
    CommandOutput co = new CommandOutput(c.getName(), c.getArm(), c.getBeard());
    itsLog.exiting(this.getClass().getName(), "retrieveCharacter ", co);
    return co;
}
Advantages:
  • no SQL/HQL/JPSQL of any kind required
  • the JPA implementation can cache the object and retrieve is quickly.
Disadvantages:
  • only for specific uses, like retrieving objects by primary key.

Conclusion

I hope to have demonstrated the different uses that exist in retrieving data from a database using any kind of ORM, compatible with the JPA. As you are no doubt aware from this piece, I strongly consider the last four examples to be good practices of creating JPQL queries in your application.

As always, each has its strong and weak points, and therefore are applicable to different situations. Evaluate the situation and pick the one that is best suited for the job.

References


[1] Java Persistence with Hibernate
Christian Bauer, Gavin King
[2] chapter 2.3 - Hibernate Community Documentation
http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/
[3] Organize Your Named JPQL Queries
http://eubauer.de/kingsware/2011/03/25/organize-your-named-jpql-queries/
[4] Hibernate: Criteria vs. HQL
http://stackoverflow.com/questions/197474/hibernate-criteria-vs-hql
[5] Are Hibernate named HQL queries (in annotations) optimised?
http://stackoverflow.com/questions/2641997/are-hibernate-named-hql-queries-in-annotations-optimised
[6] GlassFish Project - Java Persistence Example
http://glassfish.java.net/javaee5/persistence/persistence-example.html
[7] Use string constants in annotations
http://javahowto.blogspot.com/2009/04/use-string-constants-in-annotations.html
[8] Java Persistence 2.0 Public Draft: Criteria API
http://blogs.oracle.com/ldemichiel/entry/java_persistence_2_0_public1
[9] Dynamic, typesafe queries in JPA 2.0
http://www.ibm.com/developerworks/java/library/j-typesafejpa/
[10] Where to put named queries in JPA?
http://jdevelopment.nl/put-named-queries-jpa/
[11] Java Glossary
http://randomthoughtsonjavaprogramming.blogspot.com/p/glossary.html