HW2 - An object-oriented design and implementation of an annotation framework and a verifier for a design pattern.
- In this homework, I write a custom annotation processor which helps me verify the elements of the Memento design pattern. I make use of rule sets and class level verifiers to achieve my goal.
- OS : MacOS Mojave
- IDE : IntelliJ IDEA 2018.1
- Language used : Java 1.8.221
- Build tool used : Gradle 4.10.2
- As this application runs completely in compile time, it does not need to be run.
- Instructions
-
Clone the following repository : abhijeet_mohanty_cs474_hw2
-
Navigate to abhijeet_mohanty_cs474_hw2/ as
cd abhijeet_mohanty_cs474_hw2/ -
Then build and compile the project as mentioned below :
> gradle clean compileJava test build
-
- The memento design pattern is a behavioural design pattern which allows the storage and retrieval of the state of an object.
- In order to implement the design pattern, there are 3 primary elements- the caretaker, the originator and the memento.
- Memento: This is a class within which the state of an object is stored.
- Originator: This is a class which creates a memento.
- Caretaker: This is a class which stores a list of mementos and provides functionality to undo to a particular memento.
- Constraints
- The
Memento's state within a memento should only be set through a constructor and not through a setter. Also it should contain a method to get the state. - The
Caretakershould contain a memento field, save a memento method and restore a memento method. - The
Originatorshould contain a list of mementos and a method to restore a memento which returns a memento from the list of mementos.
- The
- Annotations
- In order to verify the above design pattern, I first annotate all my class level and their enclosing elements with the following annotations.
@VerifyOriginator: Annotates the class which represents an Originator@VerifyStateField- Checks if a state field is defined with the right modifier.@VerifySetStateMethod- Checks if a state field method is defined with the right modifier.@VerifySaveMementoStateMethod- Checks if a save memento method is defined with the right modifier.@VerifyRestoreMementoStateMethod- Checks if a restore memento method is defined with the right modifier.
@VerifyCaretaker: Annotates the class which represents an Caretaker@VerifyMementoField- Checks if a memento field is defined with the right modifier.@VerifyAddMementoMethod- Checks if an add memento method is defined with the right modifier.@VerifyRestoreMementoMethod
@VerifyMemento: Annotates the class which represents an Memento@VerifyState- Checks if a state field is defined with the right modifier.@VerifyMementoConstructor- Checks if a memento constructor is defined with the right modifier.@VerifyStateGetter- Checks if a state getter method is defined with the right modifier.
- NOTE : In case of a
FIELDit is expected to have theprivatemodifier and in case of aCONSTRUCTORorMETHODit is expected to use apublicmodifier
- In order to verify the above design pattern, I first annotate all my class level and their enclosing elements with the following annotations.
- Rule sets
- These classes work on elements of kind -
METHOD,CONSTRUCTORandFIELD. - I check whether it has the right kind of modifier -
privatefor fields andpublicfor methods and constructors. - For instance, consider the
CaretakerRuleSetclass. This class verifies each element annotated with@VerifyCaretaker.*and creates an instance ofVerificationResultwhich consists of the message and its kind to be printed by themessagerof the processing environment of theMementoDesignPatternVerifierProcessor. - It works similarly with other rule sets such as
MementoRuleSetandOriginatorRuleSet.
- These classes work on elements of kind -
- Class level verifiers
- These classes work on elements of kind
CLASS. - Here I verify if all the enclosing elements needed for CLASS element in the memento design pattern are defined or not.
- For instance, consider the
CaretakerClassVerifierclass. This class verifies the presence of each element annotated with@VerifyCaretaker.*and creates an instance ofVerificationResultwhich consists of the message and its kind to be printed by themessagerof the processing environment of theMementoDesignPatternVerifierProcessor. - In case an element which is needed by the CLASS is not present, a warning is printed stating that the element is not defined for that class.
- It works similarly with other class level verifiers such as
MementoClassVerifierandOriginatorClassVerifier.
- These classes work on elements of kind
- Look up
- The
VeriferAndRuleSetLookupclass couple of static final maps which determine the type of rule set and class level verifier to use based on the type of annotation. nameToRuleSetMap: In theprocessmethod in the annotation processor, theRuleSetclass to be used in order to verify an annotated element enclosed within aCLASSis looked up using this map.nameToVerifierMap: In theprocessmethod in the annotation processor, theVerifierclass to be used in order to determined if all enclosing elements required have been defined within aCLASSis looked up using this map.
- The
- The results in essence are the outputs of
messagerwhich is collected using an instance of theVerificationResultclass. - There are a total of 3 implementations of the design pattern :
Memento,Originatorand theCaretakerImproperMemento,ImproperOriginatorand theImproperCaretakerCommandwhich corresponds to theCaretaker,Snapshotto theMementoand theEditorto theOriginator
- Then, the aforementioned annotations are added to each class and the elements it encloses.
- In case an annotated element is defined incorrectly or is not present, a
warningis logged otherwise anoteis logged. - The following results produced by the annotation processor are displayed below are produced at compile time :
Note: Method declaration saveSnapshot in enclosing element Editor annotated with VerifySaveMementoStateMethod is correct
Note: Method declaration save in enclosing element Originator annotated with VerifySaveMementoStateMethod is correct
Note: Method declaration undo in enclosing element Command annotated with VerifyRestoreMementoMethod is correct
Note: Method declaration restore in enclosing element Caretaker annotated with VerifyRestoreMementoMethod is correct
Note: Method declaration makeBackup in enclosing element Command annotated with VerifyAddMementoMethod is correct
Note: Method declaration addMemento in enclosing element Caretaker annotated with VerifyAddMementoMethod is correct
Note: Variable declaration state in enclosing element ImproperOriginator annotated with VerifyStateField is correct
Note: Variable declaration text in enclosing element Editor annotated with VerifyStateField is correct
Note: Variable declaration curX in enclosing element Editor annotated with VerifyStateField is correct
Note: Variable declaration curY in enclosing element Editor annotated with VerifyStateField is correct
Note: Variable declaration selectionWidth in enclosing element Editor annotated with VerifyStateField is correct
Note: Variable declaration state in enclosing element Originator annotated with VerifyStateField is correct
Note: Variable declaration mementos in enclosing element ImproperCaretaker annotated with VerifyMementoField is correct
Note: Variable declaration backup in enclosing element Command annotated with VerifyMementoField is correct
Note: Variable declaration mementos in enclosing element Caretaker annotated with VerifyMementoField is correct
Note: Method declaration setText in enclosing element Editor annotated with VerifySetStateMethod is correct
Note: Method declaration setCursor in enclosing element Editor annotated with VerifySetStateMethod is correct
Note: Method declaration setSelectionWidth in enclosing element Editor annotated with VerifySetStateMethod is correct
Note: Method declaration setState in enclosing element Originator annotated with VerifySetStateMethod is correct
Note: Method declaration getState in enclosing element Memento annotated with VerifyStateGetter is correct
Note: Method declaration restore in enclosing element Snapshot annotated with VerifyStateGetter is correct
Note: Method declaration createSnapshot in enclosing element Editor annotated with VerifyRestoreMementoStateMethod is correct
Note: Method declaration restore in enclosing element Originator annotated with VerifyRestoreMementoStateMethod is correct
warning: Variable declaration state in enclosing element ImproperMemento annotated with VerifyState should not have public modifier.
Note: Variable declaration state in enclosing element Memento annotated with VerifyState is correct
Note: Variable declaration text in enclosing element Snapshot annotated with VerifyState is correct
Note: Variable declaration curX in enclosing element Snapshot annotated with VerifyState is correct
Note: Variable declaration curY in enclosing element Snapshot annotated with VerifyState is correct
Note: Variable declaration selectionWidth in enclosing element Snapshot annotated with VerifyState is correct
warning: Method setState in enclosing element ImproperMemento annotated with VerifyStateSettershould not be defined and field variables should be initialized only through a constructor.
Note: Constructor in enclosing element Memento annotated with VerifyMementoConstructor is correct
Note: Constructor in enclosing element Snapshot annotated with VerifyMementoConstructor is correct
warning: No element annotated with VerifySetStateMethod is defined in enclosing element ImproperOriginator
warning: No element annotated with VerifySaveMementoStateMethod is defined in enclosing element ImproperOriginator
warning: No element annotated with VerifyRestoreMementoStateMethod is defined in enclosing element ImproperOriginator
warning: No element annotated with VerifyAddMementoMethod is defined in enclosing element ImproperCaretaker
warning: No element annotated with VerifyRestoreMementoMethod is defined in enclosing element ImproperCaretaker
warning: No element annotated with VerifyMementoConstructor is defined in enclosing element ImproperMemento
warning: No element annotated with VerifyStateGetter is defined in enclosing element ImproperMemento
- A compile time usage of reflections which can verify the order in which the elements of my design pattern are used and to analyze the exact return types.
- An attempt to build a generic design pattern verifier.