Home NameOf() Expression for Java
Post
Cancel

NameOf() Expression for Java

Did you ever have the following issue: you needed to refer to a field in your code using a string literal?

Consider you have an entity that looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class User {
  private String userName;

  private String firstName;
  private String lastName;

  public String getUserName() {
    return userName;
  }

  public void setUserName(String userName) {
    this.userName = userName;
  }

  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
}

Now imagine you need to write a custom query using the JPA2 criteria API - it could maybe look somewhat like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class DataProvider {

  private final EntityManager entityManager;
  
  public DataProvider(EntityManager entityManager) {
    this.entityManager = entityManager;
  }

  public List<User> getUsersWithSameFirstName(String firstName) {
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<User> criteria = cb.createQuery(User.class);
    Root<User> root = query.from(User.class);

    ParameterExpression<String> firstNameParam = cb.parameter(String.class);

    var fieldName = "firstName";
    criteria.where(cb.equal(root.get(fieldName), firstNameParam));

    return entityManager
            .createQuery(criteria)
            .setParameter(firstNameParam, firstName)
            .getResultList();
  }

}

The problem here of course is that in line 16 you need to specify the entity’s field as a string value (in this case “firstName”) which is ugly. Imagine refactoring the field name, then this string would stay unaltered and worst case: you might only see that there is a problem during runtime (your tests should ideally also cover that and tell you before you deploy and run the code, but no test can cover 100% of possibilities).

In C# there exists a handy expression called nameof which gives you simply the name of a field - it looks like this:

1
nameof(myField)

and returns something like this:

1
"myField"

Wouldn’t it be handy to have something like that in Java as well? In case we were ever to refactor that field all the places in the source that referred to that field would automatically get updated as well (by using a modern IDE that is).

That’s why we implemented a small library that allows you to make use of this C# treat also in Java. But because we can not alter the language itself to include a nameof expression, we implemented it using some reflection trickery. Here is how line 16 from above looks like with our library:

1
var fieldName = Name.of(User.class, User::getFirstName);

As you can see, strings are not required anymore to reference the field but rather we make use of the getter to specify what field’s name we want. While this is not as elegant as its C# counterpart, it for sure solves the problem of not wanting to refer to a field using a string literal.

For your convenience we deployed the library to the Central Repository (aka Maven Central). You can simply use it in your projects using this snipped in your pom.xml:

1
2
3
4
5
<dependency>
    <groupId>de.mobiuscode.nameof</groupId>
    <artifactId>nameof</artifactId>
    <version>1.0</version>
</dependency>

Or if you prefer Gradle:

1
implementation 'de.mobiuscode.nameof:nameof:1.0'

The library is under MIT license which allows you to use it in any and all of your projects: commercial and non-commercial alike. Checkout our project at GitHub: https://github.com/mobiuscode-de/nameof.

This post is licensed under CC BY-NC-SA by the author.