Adding dynamic finder methods to an entity

The finder list command shows the candidate dynamic finder method names whose implementations Roo can automatically generate. In this recipe, we will look at how to add dynamic finder methods to a persistent entity using the finder add command. As an example, we will add the findFlightsByDestinationLikeAndOriginLike method to a Flight entity.

Getting ready

Refer to the Viewing candidate dynamic finder methods recipe, to create the flight-app Roo project.

Start the Roo shell from the C: oo-cookbookch03-recipes directory.

How to do it...

To add dynamic finder methods, follow the given steps:

  1. Set the focus of subsequent commands on the Flight entity using a focus command:
    roo> focus --class ~.domain.Flight
    
  2. Add the findFlightsByDestinationLikeAndOriginLike dynamic finder method to the Flight entity using the finder add command:
    .. roo> finder add findFlightsByDestinationLikeAndOriginLike
    
    Updated SRC_MAIN_JAVAsample
    ooflightappdomainFlight.java
    Created SRC_MAIN_JAVAsample
    ooflightappdomainFlight_Roo_Finder.aj
    

How it works...

The finder add command adds a dynamic finder method implementation to a persistent entity. This feature saves the effort of writing your own JPA-QL queries for the finder methods. The finder add command adds the name of the finder method to the finders attribute of the @RooEntity annotation (refer to Chapter 2 for more details). The presence of the finders attribute in the @RooEntity annotation triggers the creation of a *_Roo_Finder.aj ITD file (if it doesn't already exist for the entity) and auto-generation of the finder method implementation in the *_Roo_Finder.aj ITD file. *_Roo_Finder.aj adds finder method implementation to the corresponding JPA entity class.

The following figure shows how Roo adds dynamic finder methods to a JPA entity when the finder add command is executed:

How it works...

The given figure shows that when the finder add xyz command is executed, the Finder add-on of Roo adds the xyz method name to the finders attribute of the @RooElement annotation in the Flight.java file. As Spring Roo monitors Java files that are annotated with Roo's annotations, Roo uses the Finder add-on to add the xyz dynamic finder method implementation to the Flight_Roo_Finder.aj file. If Flight_Roo_Finder.aj doesn't exist, the Finder add-on creates it. Now, if you define the xyz method in the Flight.java file (because you may want to customize the implementation of the xyz method generated by Roo), the Finder add-on removes it from the Flight_Roo_Finder.aj file.

The following code shows the modified @RooEntity annotation of the Flight entity, after the finder add command is executed:

@RooEntity(identifierType = FlightKey.class,
table = "FLIGHT_TBL",
finders = { "findFlightsByDestinationLikeAndOriginLike"})

public class Flight { ... }

The following code shows the auto-generated implementation of the findFlightsByDestinationLikeAndOriginLike finder method in the Flight_Roo_Finder.aj file:

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
...
 public static TypedQuery<Flight>
   Flight.findFlightsByDestinationLikeAndOriginLike(
     String destination, String origin)
{
    
   if (destination == null || destination.length() == 0) 
      throw new IllegalArgumentException("The destination 
          argument is required");
   ...
   if (origin == null || origin.length() == 0) 
      throw new IllegalArgumentException("The origin argument 
           is required");
   ...
   EntityManager em = Flight.entityManager();
   TypedQuery<Flight> q = em.createQuery("SELECT Flight FROM 
     Flight AS flight WHERE LOWER(flight.destination) LIKE 
     LOWER(:destination)  AND LOWER(flight.origin) LIKE 
     LOWER(:origin)", Flight.class);

   q.setParameter("destination", destination);
   q.setParameter("origin", origin);
   return q;
}

The given code shows the following:

  • The finder method expects that both the origin and destination arguments must be supplied to the finder method or an exception is thrown. In general, the dynamic finder method implementation generated by Roo requires that the arguments passed to the method are not null. If an argument type is String, the dynamic finder method implementation requires that the argument must not be null or blank, as shown in this code.
  • JPA-QL for the finder method is auto-generated.
  • The return type of the finder method is javax.persistence.TypedQuery<Flight>. You can call the getResultList method of the TypedQuery object from your web controller class to execute the SELECT query and obtain the result.

There's more...

Let's now look at how we can add a custom finder method to an entity, perform integration testing of dynamic finder methods, and use a @RooEntity annotation to trigger auto-generation of a dynamic finder method implementation:

Adding custom finder methods

You may want to add custom finder methods if the dynamic finder methods offered by Roo don't meet your application's requirements. In such cases, you can either perform push-in refactoring of Roo-generated dynamic finder methods and modify their implementation (not their name or signature) in the corresponding persistent entity Java class or you can define the method in the persistent entity Java class (which will result in removing the method from the *_Roo_Finder.aj AspectJ ITD) or you can create your own AspectJ ITD to introduce your custom finder methods into the persistent entity Java class.

If you want to change the implementation of a dynamic finder method, then you can either use push-in refactoring or you can define the method in persistent entity Java class. The effects of using push-in refactoring or defining the method in persistent entity Java class are the same. In push-in refactoring, you use the IDE to move a declaration from AspectJ ITD file to the target Java class and then modify it. And, in case you decide to define the method in the Java class itself, you will probably do a copy-paste from AspectJ ITD to the Java class, and let Roo remove the method declaration from AspectJ ITD.

The following figure shows what happens when you use push-in refactoring to move a method declaration from AspectJ ITD to the target Java ss:

Adding custom finder methods

The given figure shows that when you perform push-in refactoring of the findFlightsByDestinationLikeAndOriginLike method, the IDE simply moves the method from the AspectJ ITD file to the target Flight.java class. So, if you have to customize a method such as findFlightsByDestinationLikeAndOriginLike by writing it in the Flight.java class, it will be much simpler if you perform push-in refactoring or simply copy the method from the AspectJ ITD file and paste it in the Flight.java class (followed by removing the Flight. that is prefixed to the method name). Copy-pasting from AspectJ ITDs to target Java classes isn't efficient if you are planning to move all the declarations in all the AspectJ ITDs to target Java classes. This is where push-in refactoring is helpful, as we will see in Chapter 7, Developing Add-ons and Removing Roo from Projects.

If you want to add a custom finder method whose name or signature is different from the dynamic finder methods offered by Roo, then you can either define the method in the persistent entity Java class or you can create a new AspectJ ITD and declare your method in it. Both these approaches are fine, and it depends upon how comfortable you are with writing AspectJ ITDs. Roo generates AspectJ ITDs so that cross-cutting concerns are separate from the Java classes. So, if you feel that writing finder methods in your persistent entity Java class pollutes it, you should consider writing AspectJ ITDs. It is important to note that the custom AspectJ ITDs that you create in your project are not managed by Roo.

The following code shows an example of the Flight_MyCustom_Finder.aj AspectJ ITD, which introduces the searchFlights(SearchCriteria criteria) finder method into Flight.java:

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

privileged aspect Flight_MyCustom_Finder {
    
  public static TypedQuery<Flight> Flight.searchFlight(
      SearchCriteria criteria) {
    EntityManager em = Flight.entityManager();
    TypedQuery<Flight> q = em.createQuery("SELECT Flight ..", 
      Flight.class);
    q.setParameter("destination", criteria.getDestination());
    q.setParameter("origin", criteria.getOrigin());
    return q;
  }
}

As the given code shows, you can create your own AspectJ ITD and add custom finder methods to JPA entities. As custom AspectJ ITDs are not managed by Roo, if you create the searchFlight method in the Flight.java class, Roo will not remove it from the Flight_MyCustom_Finder.aj file.

Integration testing of dynamic finder methods

Roo doesn't create integration tests for the auto-generated dynamic finder methods. To test finder methods, write the test method in the *IntegrationTest.java file corresponding to the persistent entity.

Adding dynamic finders through @RooEntity annotation

The @RooEntity annotation accepts a finders attribute, which contains an array of string values identifying names of dynamic finder methods that must be generated for the persistent entity. The finders add command adds the finder method name to the finders attribute, which in turn results in the generation of dynamic finder method by Roo. As the addition of finder method name to finders attribute triggers generation of dynamic finder method implementation, instead of using the finder add command you can directly add the name of the finder method to the finders attribute using IDE, which in turn will trigger Roo to generate the finder method implementation.

See also

  • Refer to the Controlling auto-generated methods of persistent entities recipe in Chapter 2, Persisting Objects Using JPA to know more about the elements supported by the @RooEntity annotation
  • Refer to the Viewing candidate dynamic finder methods recipe to see how the finder list command is used to show the names of candidate dynamic finder methods
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.114.19