Augmentations
enable adding implementations of interfaces to an existing class that you cannot modify (for example, the source comes from an external dependency). An augmentation extends the Augmentation
class and specifies the interface to be implemented, for example:
public class MyAugmentation extends Augmentation<TargetClass> implements NewInterface {
public void ImplementedMethod(...) {
}
}
The implemented methods in an augmentation extend the functionality of the class that is the target of the augmentation, but the augmentation does not change the target class itself. An augmentation can return an instance of the target class with the Augmentation#getOriginalObject
method, allowing the augmentation to invoke methods originally defined on the target class.
Client code can access augmentation methods with the method, which converts the state of an object into an instance of the target augmentation class. To determine if an object’s state can be converted into an instance of the augmentation class, use the State.isInstantiableTo(Class<?>)
method.
As an example, consider a new requirement applied to an existing site. Instances of some Content
types — Article
, Image
, and Video
—must be downloadable if certain conditions are met. That is, an Article
, Image
, or Video
object can be downloaded if it satisfies a download rule applied to each type. Each type has a different download rule. For the Article
type, instances must be available for download 60 days after the publication date. For Image
and Video
types, different rules determine their availability for download.
To accommodate the requirement, a new interface, Downloadable
, must be added, along with three augmentations for the Article
, Image
, and Video
types. Each augmentation will implement Downloadable
differently, to reflect the fact that different download rules apply for Article
, Image
, and Video
.
Step 1: Create the interface
The interface declares one method. Implementations of the isDownloadable
method will determine if an Article
, Image
, or Video
object is eligible for download.
public interface Downloadable {
boolean isDownloadable();
}
Step 2: Create the augmentations
A different augmentation is required for the Article
, Image
, and Video
types, each of which implements the isDownloadable
method differently. The following example shows the implementation for the Article
class. (Implementations for Video
and Image
would be different.) The method returns true
if an article was published 60 or more days prior to the current date. The Augmentation#getOriginalObject
method is used to get the publish date from the Article
object.
import com.psddev.dari.db.Augmentation;
public class ArticleAugmentation extends Augmentation<Article> implements Downloadable {
public boolean isDownloadable() {
Date publishDate = getOriginalObject().getPublishDate();
Date todayDate = Calendar.getInstance().getTime();
long duration = todayDate.getTime() - publishDate.getTime();
return (TimeUnit.MILLISECONDS.toDays(duration) >= 60);
}
}
Step 3: Retrieve augmented objects
A client can use code similar to the following to identify instances of Content
types that are eligible for download. The snippet queries for instances of the Content
type. For each result of the query, the code tests if the object is downloadable; that is, if the class of the object has been augmented with the Downloadable
interface. If the object is of type Article
, Image
, or Video
, the object is converted to the applicable augmentation type, and the augmentation’s isDownloadable
method is called. If the method returns true
, the Article
, Image
, or Video
object is listed in the results with a download link. Otherwise, the object is listed in the results without a download link.
List<Content> objects = Query.from(Content.class).selectAll();
for (Content object : objects) {
if (object.isInstantiableTo(Downloadable.class)) {
if (object.getClass() == Article.class && object.as(ArticleAugmentation.class).isDownloadable()) {
/* Invoke code to make Article object downloadable */
continue;
} else if (object.getClass() == Image.class && object.as(ImageAugmentation.class).isDownloadable()) {
/* Invoke code to make Image object downloadable */
continue;
} else if (object.getClass() == Video.class && object.as(VideoAugmentation.class).isDownloadable()) {
/* Invoke code to make Video object downloadable */
continue;
} else /* Add object to result without download link. */
}
else // Add object to result without download link.
}
-
Retrieves all objects that inherit from the
Content
class, which are then iterated by thefor loop
that follows. -
Tests that the object's state can be converted into an instance of a
Downloadable
class. -
A series of conditions to determine if the object satisfies the download rules as implemented in the augmentation's
isDownloadable
method.