July 20, 2016

Version Number Strategy

Abstract

I am working on a new open source project named Riviera. The purpose of Riviera is to be a database versioning source code management tool. Riviera is a Java based implementation of the philosophy and practice of database version control written about by K. Scott Allen. But before Riviera can manage changing database versions, it first must know how those numbers are going to change. The purpose of this post is to define a clear strategy for understanding how version numbers change throughout the software development life cycle.

Numbers

Versions will consist of 4 integers separated by dots with an optional dash qualifier at the end. The format for a version number is A.B.C.D[-QUALIFIER]. Let’s take a look at what each of these numbers mean.

A

This represents a major version. This number is used by a project manager to track releases. How and when this number changes is up to the project. Most like to change this number when a significant change is made to the project. Others like to change this number on a yearly basis. Determine how you want to change this number and stay consistent. Major versions can’t get to production without planned releases, which is what’s next, B.

B

This represents a planned release of the major version. This value increments every planned release. A.B together are critical for project managers to plan, estimate, and track features in releases.
NOTE Planning releases? What about Scrum? What about development teams determining what to work on each sprint, scrum masters, and no project managers? Well, if you are working in an environment like this, congratulations! Now back to reality :)
Suppose a new project is spinning up. Project managers start planning for release “1.0” - which is the 1st planned release 0 of major version 1. This release will include features f1, f2, & f3.
While developers are working on “1.0”, project managers can start planning for release “1.1” - which is the 2nd planned release 1 of major version 1. This release will include features f4 & f5.
And so planning continues following this pattern. The scope of features for A.B is determined and the development team works on them. This planning works great until a bug is found in production. To get emergency bug fixes, C is needed.

C

This represents an emergency bug fix of a planned release. Recall that a planned release is represented by A.B. An emergency bug fix of A.B is represented by A.B.C. A.B.C together are critical for project managers to plan, estimate, and track bug fixes.
If a bug is found in “1.3”, and must be fixed in production immediately, the 1st bug fix of “1.3” will be “1.3.1”. Once “1.3.1” goes to production, the C version number keeps incrementing as more emergency bug fixes need to be made:
  • “1.3.1” – 1st emergency bug fix of “1.3”
  • “1.3.2” – 2nd emergency bug fix of “1.3”
  • “1.3.3” – 3rd emergency bug fix of “1.3”
  • “1.3.4” – 4th emergency bug fix of “1.3”
Project managers can plan releases all they want, but nothing will get done unless the software gets built. D makes sure builds can happen. Let’s take a look at D next.

D

This represents an incremental build number. This number is typically manged by some automated build system (Maven) and is used for internal purposes only.
The build number tracks the number of builds made of a planned release or an emergency bug fix. Let’s take a look at each of these.

Incremental build of a planned release.

Suppose the development team is working on planned release “1.3”. As features are finished, builds are made for testing. Each build increments the D value.
  • 1.3.0.0 – 1st build of planned release “1.3”
  • 1.3.0.1
  • 1.3.0.2
  • 1.3.0.3
  • 1.3.0.4
Ultimately, when “1.3” is finished and ready to go to production, the internally tracked build going to production may be 1.3.0.15.

Incremental build of emergency bug fix.

Suppose the development team is working on emergency bug fix “1.3.1”. As the bugs are fixed, builds are made for testing. Each build increments the D value.
  • 1.3.1.0 – 1st build of emergency bug fix “1.3.1”
  • 1.3.1.1
  • 1.3.1.2
  • 1.3.1.3
Ultimately, when the “1.3.1” is finished and ready to go to production, the internally tracked build going to production may be 1.3.1.4.

[-QUALIFIER]

This is an optional part of a version number. Maven uses -SNAPSHOT to represent non-official builds.

GIT, Subversion, CVS, etc.

Now that the format of the version number has been defined, let’s consider the effects on the change control system (GIT, Subversion, CVS, etc.). To do this, we’ll follow a hypothetical development time line. As you read through the time line, reference figure 1 to see how the trunk, branches, and tags change over time.

Time Line

  • Planning for the “1.0” release is complete. Development starts. Trunk is at 1.0.0.0 (a).
  • “1.0” features completed. A build is made for testing. Tag 1.0.0.0 is created from trunk. Trunk becomes 1.0.0.1 (b)
  • “1.0” features completed. A build is made for testing. Tag 1.0.0.1 is created from trunk. Trunk becomes 1.0.0.2 (c)
  • “1.0” features completed. A build is made for testing. Tag 1.0.0.2 is created from trunk. Trunk becomes 1.0.0.3 (d)
  • Planning for “1.1” release is complete. Branch 1.0.0 is created for ongoing “1.0” development. Trunk becomes 1.1.0.0 and “1.1” development starts on trunk. (e)
  • “1.0” features completed. A build is made for testing. Tag 1.0.0.3 is created from branch. Branch becomes 1.0.0.4. Changes from branch merged into trunk. (f)
  • “1.1” features complete. A build is made for testing. Tag 1.1.0.0 is created from trunk. Trunk becomes 1.1.0.1 (g)
  • “1.0” features completed. A build is made for testing. Tag 1.0.0.4 is created from branch. Branch becomes 1.0.0.5. Changes from branch merged into trunk. (h)
  • “1.1” features complete. A build is made for testing. Tag 1.1.0.1 is created from trunk. Trunk becomes 1.1.0.2 (i)
  • “1.0” FINISHED. Build 1.0.0.4 goes to production (j)
  • “1.1” features complete. A build is made for testing. Tag 1.1.0.2 is created from trunk. Trunk becomes 1.1.0.3 (k)
  • “1.1” features complete. A build is made for testing. Tag 1.1.0.3 is created from trunk. Trunk becomes 1.1.0.4 (l)
  • “1.1” features complete. A build is made for testing. Tag 1.1.0.4 is created from trunk. Trunk becomes 1.1.0.5 (m)
  • “1.0” EMERGENCY BUG FIX. Create branch from 1.0.0.4 tag (the build in production). Branch becomes 1.0.1.0 (n)
  • “1.0.1” EMERGENCY BUG FIX complete. A build is made for testing. Tag 1.0.1.0 is created from branch. Branch becomes 1.0.1.1. Changes in branch merged into trunk (o)
  • “1.0.1” EMERGENCY BUG FIX complete. A build is made for testing. Tag 1.0.1.1 is created from branch. Branch becomes 1.0.1.2. Changes in branch merged into trunk (p)
  • “1.1” features complete. A build is made for testing. Tag 1.1.0.5 is created from trunk. Trunk becomes 1.1.0.6 (q)
  • “1.0.1” EMERGENCY BUG FIX complete. A build is made for testing. Tag 1.0.1.2 is created from branch. Branch becomes 1.0.1.3. Changes in branch merged into trunk (r)
  • “1.0.1” FINISHED. Build 1.0.1.2 goes to production (s)
  • And it continues…

Figure 1 - Trunk, Branches, & Tags

 TRUNK
1.0.0.0------                                       (a)
   |         \
   |         TAG
   |       1.0.0.0                                  (b)
   |
1.0.0.1------                                       (b)
   |         \
   |         TAG
   |       1.0.0.1                                  (c)
   |
1.0.0.2------                                       (c)
   |         \
   |         TAG
   |       1.0.0.2                                  (d)
   |
1.0.0.3------                                       (d)
   |         \
   |       BRANCH
   |       1.0.0.3------                            (e)
   |          |         \
   |          |         TAG
   |          |       1.0.0.3                       (f)
   |          |
   |       1.0.0.4------                            (f)
   |          |         \
   |          |         TAG------
   |          |       1.0.0.4    \                  (h) (j)
   |          |                 BRANCH------
   |       1.0.0.5              1.0.1.0     \       (h) (n)
   |          |                    |        TAG
   |          -                    |      1.0.1.0   (o)
   |                               |
   |                            1.0.1.1------       (o)
   |                               |         \
   |                               |        TAG
   |                               |      1.0.1.1   (p)
   |                               |
   |                            1.0.1.2------       (p)
   |                               |         \
   |                               |        TAG
   |                               |      1.0.1.2   (r) (s)
   |                               |
   |                            1.0.1.3             (r)
   |
1.1.0.0------                                       (e)
   |         \
   |         TAG
   |       1.1.0.0                                  (g)
   |
1.1.0.1------                                       (g)
   |         \
   |         TAG
   |       1.1.0.1                                  (i)
   |
1.1.0.2------                                       (i)     
   |         \
   |         TAG
   |       1.1.0.2                                  (k)
   |
1.1.0.3------                                       (k)     
   |         \
   |         TAG
   |       1.1.0.3                                  (l)
   |
1.1.0.4------                                       (l)     
   |         \
   |         TAG
   |       1.1.0.4                                  (m)
   |
1.1.0.5------                                       (m)     
   |         \
   |         TAG
   |       1.1.0.5                                  (q)
   |
1.1.0.6                                             (q)

Summary

Handling version numbers is always a tricky thing, especially when you have multiple lines of development going on different branches and all the work needs to be coordinated and merged. This strategy seems to work well. The hard part is sticking to it!

References

Allen, S. (2008, February 4). Versioning Databases - Branching and Merging. Ode to Code. Retrieved from http://odetocode.com/blogs/all?page=75.

July 19, 2016

Welcome to Scrivener

Abstract

Begin typing your abstract paragraph here. This paragraph should not be indented. It should range between 150 and 250 words. This should be accurate, nonevaluative, readable, and concise. The reader should know exactly what this blog post is about.

Scrivener

Scrivener is a powerful writing tool which can be used for all kinds of writing. Originally developed for writing novels, Scrivener is now used for short stories, plays, scripts, theses, and lots of other kinds of writing including blogging.

Scrivener separates the content of what you write from its output format. Compiling is how to get the output format. For bloggers, Scrivener supports the markdown syntax. Let’s take a look at markdown.

Markdown

Markdown is a markup format for writers that’s easier than HTML, but is ultimately turned into HTML. A cheat sheet shows just how simple it is. Scrivener compiles a markdown formatted writing into HTML. After that, copy & paste the HTML into the HTML Editor of your blogging platform.

NOTE The HTML generated is quite simple. Your blog’s CSS will need to be updated to present it nicely. Typically somewhere in the settings you’ll find a spot to edit the contents of the blog template. It’s here you can add custom CSS to format the markdown-generated HTML.

Code

All technical blogs will need to show code. There will be int inlineCode = 1; examples. And there will be block code examples referred to by listings. Listing 1 is a Java block code example.

Listing 1 - Java Hello World

public static final void main(String [] args) {
  System.out.println("Hello world!");
}

Images

Images are also essential. Figure 1 is an example of an image. This image is not embedded in the blog. It is referencing an image from another website. This is a bit dangerous to do because if the website removes the image, it will no longer appear on the blog. An alternative is to upload images to the blog and reference the URLs created for those images. Or host the images on a site like Flickr. Or save the images to Dropbox and get a shared link to the image.

Figure 1 - Duke

Java Duke waving
Java Duke waving

Summary

It is always good to wrap up a blog posting with a summary of the contents. Sometimes blog posts are small quick tips and a summary is not necessary. But if the blog post is presenting lengthy contents, then a summary is good to help remind blog readers what they just read.

References

And don’t forget your references! People contribute a lot of information online, so it’s good to cite your sources.

Pritchard, A. (2016, February 26). Markdown Cheatsheet. Website Title. Retrieved from https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet

June 20, 2016

Unit Testing JPA...Stop Integration Testing!

Introduction
I want to start by asking a simple question.
"How do you unit test your JPA classes?"
Now, before you answer look carefully at the question.  The key words are unit test.  Not test but unit test.

Conversation
In my experience, after asking this question, the conversation goes something like this.
"How do you unit test your JPA domain objects?"
"We've developed this shared project which starts an in-memory Derby database (See my previous blog article about how to do this for integration testing) and it automatically runs scripts in your project to build the database and insert data for the tests."
 "Where is this shared project?"
"It's in Nexus.  We pull it in as a Maven dependency."
"I see it in the POM.  You know this dependency doesn't have <scope>test</scope>"
 "Huh?"
"Never mind.  Where's the source code for the project?"
 "The person who made it doesn't work here anymore so we don't know where the source code is.  But we haven't had to change it."
"Where's the documentation?"
"Umm...we just copy stuff from existing projects and change the DDLs and queries"
"Why are you starting Derby for a unit test?  Unit tests must be easy to maintain and fast to run.  You can't be starting any frameworks like JPA or relying on external resources like a database.  They make the unit tests complicated and slow running."
 "Well, the classes use JPA, you need a database to test them."
"No, you don't.  You don't need to start a database.  JPA relies heavily on annotations.   All you need to do is make sure all the classes, fields, and getters are annotated correctly. So just unit test the annotations and the values of their properties."
"But that won't tell you if it works with the database."
"So?  You are supposed to be writing simple and fast unit tests! Not integration tests! For a unit test all you need to know is if the JPA classes are annotated properly. If they're annotated properly they'll work."
"But what if the databases changes?"
"Good question, but not for a unit test.  For a unit test all you need to know is that what was working before is still working properly.  For frameworks like JPA that depend on annotations to work properly, your unit tests need to make sure the annotations haven't been messed around with."
"But how do you know if the annotations are right? You have to run against a database to get them right."
"Well, what if you weren't using JPA, what if you were writing the SQL manually?  Would you right a unit test to connect to the a database and keep messing around with the SQL in your code until you got it right?  Of course not.  That would be insane!  Instead, what you would do is use a tool like SQL Developer, connect to the database, and work on the query until it runs correctly.  Then, after you've gotten the query correct, you'd copy and paste the query into your code.  You know the query works - you just ran it in SQL Developer - so no need to connect to a database from your unit test at all.  Your unit test only needs to assert that the code generates the query properly.  If you are using JPA, it's fundamentally the same thing.  The difference is with JPA you need to get the annotations correct.  So, do the JPA work somewhere else, then, when you got it correct, copy & paste it into your project and unit test the annotations."
"But where do you do this work?  Can SQL Developer help figure out JPA annotations?....Wait! I think Toad can.  Do we have more licenses for that?"
"Ugh!  No!  You create a JPA research project which starts a JPA implementation so you can play around with the JPA annotations.  In this research project, ideally you'd connect to the real project's development database, but you can actually connect to whatever database that has the data you need.  Doing all this work in a research project is actually much better for the real project because you get rid of the in-memory database from the real project and you also get rid of trying to replicate your project's real database in Derby.
"Where do we get a research project like this?"
"Umm, you just create one; Right-click -> Create -> New project." 
 "You mean everyone has to create their own research project?  Seems like a waste."
"Ugh!"
If you have had a conversation similar to this, please let me know.  I'd love to hear your stories. 

Example
But with this all being said, how do you unit test the annotations of you JPA objects.  Well it's not really that difficult.  The Java reflection API give access to a classes annotations.  So let's see what this might look like.

Suppose listing 1 is a Person object.  This Person object is part of your domain model and is setup to be handled by JPA to persist data to the database. 

Listing 1: Person and Phone Object Model
package org.thoth.jpa.UnitTesting;

import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

/**
 * (JavaCodeGeeks, 2015)
 */
@Entity
@Table(name = "T_PERSON")
  public class Person {

  private Long id;
  private String firstName;
  private String lastName;
  private List<Phone> phones = new ArrayList<>();

  @Id
  @GeneratedValue()
  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  @Column(name = "FIRST_NAME")
  public String getFirstName() {
    return firstName;
  }

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

  @Column(name = "LAST_NAME")
  public String getLastName() {
    return lastName;
  }

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

  @OneToMany(mappedBy = "person", fetch = FetchType.LAZY)
  public List<Phone> getPhones() {
    return phones;
  }
}

The code in listing 1 is just an example, so it's very simple.  In real applications, the domain objects and their relationships to other objects will get complex.  But this is enough for demonstration purposes.  Now, the next thing you want to do is unit test this object. Remember, the key words are unit test. You don't want to be starting any frameworks or databases.  It's the annotations and their properties which make the Person object work properly, so that's what you want to unit test.  Listing 2 shows what a unit test for the Person object may look like.

Listing 2: PersonTest Unit Test

package org.thoth.jpa.UnitTesting;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.junit.Assert;
import org.junit.Test;

/**
 * @author Michael Remijan mjremijan@yahoo.com @mjremijan
 */
public class PersonTest {
  @Test
  public void typeAnnotations() {
    // assert
    AssertAnnotations.assertType(
        Person.class, Entity.class, Table.class);
  }


  @Test
  public void fieldAnnotations() {
    // assert
    AssertAnnotations.assertField(Person.class, "id");
    AssertAnnotations.assertField(Person.class, "firstName");
    AssertAnnotations.assertField(Person.class, "lastName");
    AssertAnnotations.assertField(Person.class, "phones");
  }


  @Test
  public void methodAnnotations() {
    // assert
    AssertAnnotations.assertMethod(
        Person.class, "getId", Id.class, GeneratedValue.class);

    AssertAnnotations.assertMethod(
        Person.class, "getFirstName", Column.class);

    AssertAnnotations.assertMethod(
        Person.class, "getLastName", Column.class);

    AssertAnnotations.assertMethod(
        Person.class, "getPhones", OneToMany.class);
  }


  @Test
  public void entity() {
    // setup
    Entity a
    = ReflectTool.getClassAnnotation(Person.class, Entity.class);

    // assert
    Assert.assertEquals("", a.name());
  }


  @Test
  public void table() {
    // setup
    Table t
    = ReflectTool.getClassAnnotation(Person.class, Table.class);

    // assert
    Assert.assertEquals("T_PERSON", t.name());
  }


  @Test
  public void id() {
    // setup
    GeneratedValue a
    = ReflectTool.getMethodAnnotation(
        Person.class, "getId", GeneratedValue.class);

    // assert
    Assert.assertEquals("", a.generator());
    Assert.assertEquals(GenerationType.AUTO, a.strategy());
  }


  @Test
  public void firstName() {
    // setup
    Column c
    = ReflectTool.getMethodAnnotation(
        Person.class, "getFirstName", Column.class);

    // assert
    Assert.assertEquals("FIRST_NAME", c.name());
  }


  @Test
  public void lastName() {
    // setup
    Column c
    = ReflectTool.getMethodAnnotation(
        Person.class, "getLastName", Column.class);

    // assert
    Assert.assertEquals("LAST_NAME", c.name());
  }


  @Test
  public void phones() {
    // setup
    OneToMany a
    = ReflectTool.getMethodAnnotation(
        Person.class, "getPhones", OneToMany.class);

    // assert
    Assert.assertEquals("person", a.mappedBy());
    Assert.assertEquals(FetchType.LAZY, a.fetch());
  }
}

For this unit test, I created a couple simple helper classes: AssertAnnotations and ReflectTool since these can obviously be reused in other tests.  AssertAnnotations and ReflectTool are shown in listing 3 and 4 respectively.  But before moving on to these helper classes, let's look at PersonTest in more detail.

Line 19 is the #typeAnnotations method.  This method asserts the annotations on the Person class itself.  Line 21 calls the #assertType method and passes Person.class as the first parameter then after that the list of annotations expected on the class.  It's important to note the #assertType method will check that the annotations passed to it are the only annotations on the class. In this case, Person.class must only have the Entity and Table annotations.  If someone adds an  annotation or removes an annotation, #assertType will throw an AssertionError.

Line 27 is the #fieldAnnotations method. This method asserts the annotations on fields of the Person class.  Lines 29-32 call the #assertField method.  The first parameter is Person.class.  The second parameter is the name of the field.  But then after that something is missing; where is the list of annotations?  Well in this case there are no annotations!  None of the fields in this class are annotated.  By passing no annotations to the #assertField method, it will check to make sure the field has no annotations.  Of course if you JPA object uses annotations on the fields instead of the getter method, then you would put in the list of expected annotations.  It's important to note the #assertField method will check that the annotations passed to it are the only annotations on the field. If someone adds an annotation or removes an annotation, #assertField will throw an AssertionError.

Line 37 is the #methodAnnotations method.  This method asserts the annotations on the getter methods of the Person class. Lines 39-49 call the #assertMethod method.  The first parameter is Person.class.  The second parameter is the name of the getter method.  The remaining parameters are the expected annotations.  It's important to note the #assertMethod method will check that the annotations passed to it are the only annotations on the getter.  If someone adds an annotation or removes an annotation, #assertMethod will throw an AssertionError.  For example, on line 40, the "getId" method must only have the Id and GeneratedValue annotations and no others.

At this point PersonTest has asserted the annotations on the class, its fields, and its getter methods.  But, annotations have values too.  For example, line 17 of the Person class is @Table(name = "T_PERSON").  The name of the table is vitally important to the correct operation of this JPA object so the unit test must make sure to check it.

Line 64 is the #table method.  It uses the ReflectTool on Line 68 to get the Table annotation from the Person class.  Then line 71 asserts the name of the table is "T_PERSON".

The rest of the unit test method in PersonTest assert the values of the annotations in the Person class.  Line 83 asserts the GeneratedValue annotation has no generator and Line 84 asserts the generation type.  Lines 96 and 108 assert the names of the database table columns.  Lines 120-121 assert the relationship type between the Person object and the Phone object.

After looking at PersonTest in more detail, let's look at help classes: AssertAnnotations and ReflectTool.  I'm not going to say anything about these classes; they aren't all that complicated.

Listing 3: AssertAnnotations helper

package org.thoth.jpa.UnitTesting;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.List;

/**
 * @author Michael Remijan mjremijan@yahoo.com @mjremijan
 */
public class AssertAnnotations {
  private static void assertAnnotations(
      List<Class> annotationClasses, List<Annotation> annotations) {
    // length
    if (annotationClasses.size() != annotations.size()) {
      throw new AssertionError(
        String.format("Expected %d annotations, but found %d"
          , annotationClasses.size(), annotations.size()
      ));
    }

    // exists
    annotationClasses.forEach(
      ac -> {
        long cnt
          = annotations.stream()
            .filter(a -> a.annotationType().isAssignableFrom(ac))
            .count();
        if (cnt == 0) {
          throw new AssertionError(
            String.format("No annotation of type %s found", ac.getName())
          );
        }
      }
    );
  }


  public static void assertType(Class c, Class... annotationClasses) {
    assertAnnotations(
        Arrays.asList(annotationClasses)
      , Arrays.asList(c.getAnnotations())
    );
  }


  public static void assertField(
      Class c, String fieldName, Class... annotationClasses) {
    try {
      assertAnnotations(
        Arrays.asList(annotationClasses)
        , Arrays.asList(c.getDeclaredField(fieldName).getAnnotations())
      );
    } catch (NoSuchFieldException nsfe) {
      throw new AssertionError(nsfe);
    }
  }


  public static void assertMethod(
      Class c, String getterName, Class...annotationClasses) {
    try {
      assertAnnotations(
        Arrays.asList(annotationClasses)
        , Arrays.asList(c.getDeclaredMethod(getterName).getAnnotations())
      );
    } catch (NoSuchMethodException nsfe) {
      throw new AssertionError(nsfe);
    }
  }
}

Listing 4: ReflectTool helper

package org.thoth.jpa.UnitTesting;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author Michael Remijan mjremijan@yahoo.com @mjremijan
 */
public class ReflectTool {
  public static <T extends Annotation> T getMethodAnnotation(
      Class<?> c, String methodName, Class<T> annotation) {
    try {
      Method m = c.getDeclaredMethod(methodName);
      return (T)m.getAnnotation(annotation);
    } catch (NoSuchMethodException nsme) {
      throw new RuntimeException(nsme);
    }
  }

  public static <T extends Annotation> T getFieldAnnotation(
      Class<?> c, String fieldName, Class<T> annotation) {
    try {
      Field f = c.getDeclaredField(fieldName);
      return (T)f.getAnnotation(annotation);
    } catch (NoSuchFieldException nsme) {
      throw new RuntimeException(nsme);
    }
  }

  public static <T extends Annotation> T getClassAnnotation(
      Class<?> c, Class<T> annotation) {
    return (T) c.getAnnotation(annotation);
  }
}

That's it.  I hope this is helpful.

References
https://www.javacodegeeks.com/2015/02/jpa-tutorial.html#relationships_onetomany