The aims of the assignment are:
The following are provided in the fridge directory (zip file)
The servlet descriptor file web.xml (directory fridge/WEB-INF): You will need to edit this file.
The jar files for JSON conversion and JDBC (MySQL) driver (directory fridge/WEB-INF/lib)
The following files are in the directory fridge/WEB-INF/classes:
Study the Validation Framework provided (complete code provided) as well as the lecture and lab materials that covered Java Reflection, Annotations and the Validation Framework.
There are two controller classes. GroceryController and ItemController. These are the bridge between the FridgeDSC class and the FridgeRouterServlet class.
Study the complete FridgeDSC.java file provided, paying attention to its constructor. Some changes have been made, which differs from Assignment 1.
NOTE: the constructor requires database host, username and password as arguments. In the tomcat service these are obtain from the web.xml file.
For each controller (GroceryController.java and ItemController.java) complete each of the "TODO" method stubs provided. Each method stub needs to make a call to a relevant FridgeDSC.java method. Identify which one and code it in the controllers and return the right data.
You may want to test if the controllers are responding properly when calling each FridgeDSC method - a static main method has been provided in each class for you to add your testing code.
The bulk of the work for this assignment is in the servlet (FridgeRouterServlet class)
The purpose of this servlet class is to use tomcat's HttpServletRequest method to;
General steps
Carefully read the class java file and complete the TODO stubs. The provided code and your completed TODOs does the following;
Using the Servlet API the class retrieves URL and http method information, and your database host, username and password from the servlet descriptor file web.xml. (add your MySQL username and password where needed in file web.xml)
Uses normal Java string manipulation to find the requested controller names from the url path information. i.e GroceryController or ItemController.
Uses the Reflection API to find and create an instance of the required controller class, and calls the appropriate method, translating information from JSON if needed, and populating the HttpServletResponse object(response) with the results. Note:
Makes sure any potential errors are caught, identified and sent back to the browser (using GSON to convert messages to JSON) and using appropriate HTTP Status Codes and adequate (descriptive) error messages.
You will use Postman to test your API (https://www.getpostman.com/) - More on Postman will be covered in your lab sessions.
TODO # | Location (file name) | Description |
1 | Grocery.java | annotation |
2 | Grocery.java | annotation |
3 | Grocery.java | annotation |
4 | Grocery.java | annotation |
5 | Grocery.java | annotation |
6 | GroceryController.java | complete get() |
7 | GroceryController.java | complete get(id) |
8 | GroceryController.java | complete getAllExpiredItems() |
9 | GroceryController.java | complete add() validation |
10 | GroceryController.java | complete add() |
11 | GroceryController.java | complete update() |
12 | GroceryController.java | complete delete() |
13 | ItemController.java | complete get() |
14 | FridgeRouterServlet.java | Set the response CONTENT_TYPE and CHARACTER_ENCODING |
15 | FridgeRouterServlet.java | Get the path info from the HttpServletRequest argument. |
16 | FridgeRouterServlet.java | Get the http method from the HttpServletRequest argument. |
17 | FridgeRouterServlet.java | Get the data model name from pathInfoArray |
18 | FridgeRouterServlet.java | Find the modelClass using String modelName |
20 | FridgeRouterServlet.java | Find the modelId in pathInfoArray (don't forget to parse to int) |
21 | FridgeRouterServlet.java | Identify the method get() with no id |
22 | FridgeRouterServlet.java | Invoke the method on the controller instance |
23 | FridgeRouterServlet.java | Find the modelId in pathInfoarray (don't forget to parse to int) |
24 | FridgeRouterServlet.java | Identify the method update() with id |
25 | FridgeRouterServlet.java | Invoke the method on the controller instance, passing modelId |
26 | FridgeRouterServlet.java | Find the modelId in pathInfoarray (don't forget to parse to int) |
27 | FridgeRouterServlet.java | Identify the method delete() with id |
28 | FridgeRouterServlet.java | Invoke the method on the controller instance, passing modelId |
29 | FridgeRouterServlet.java | Identify instances of the UpdateNotAllowedException exception |
30 | FridgeRouterServlet.java | Identify instances of the ValidationException exception |
Provide API style reference USER documentation for the use of your API. This could be via javadoc, or a word document. It should be at a level that a Web programmer wanting to use your API could use it to add data to their web application. This means for the eight end points we support you need to provide;
You should be able to do this in half a page. One page at the most. Be terse but be correct.
CharCount.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** Define annotation interface CharCount.
* If both params gets defaults, Validator should through error.
* Only applies to String; If not String, Validator should through error.
*/
@Retention(RetentionPolicy.RUNTIME)
// Process this annotation at runtime
@Target(ElementType.FIELD)
// This is an annotation on a field (attribute)
public @interface CharCount {
public int min() default 0;
public int max() default 0;
}
MissingArgumentException.java
public class MissingArgumentException extends Exception {
private static final long serialVersionUID = 1L;
public MissingArgumentException() {
super();
}
public MissingArgumentException(String message) {
super(message);
}
}
Validator.java
import java.lang.reflect.*;
import java.lang.annotation.Annotation;
import java.util.*;
public abstract class Validator {
public abstract void applyRule(
Annotation annotation,
Object fieldValue,
Class< ?> fieldType
) throws Exception;
public static final String APPLY_RULE_METHOD_NAME = "applyRule";
private static Map< String, Object> validatorMap = new HashMap< String, Object>();
// NOTE: this method is static; it could have been placed in any other Class.
// we've put it in this abstract class because it is related to the overall
// validation use case that includes this "Validator" abstract class.
public static void validate(Object model) throws Exception {
if (model == null)
throw new ValidationException(
String.join(" ", "Model [", model.getClass().getName(), "] cannot be null")
);
List< Field> fields = getInheritedDeclaredFields(model);
for(Field field: fields) {
Annotation[] annotations = field.getDeclaredAnnotations();
for(Annotation annotation: annotations) {
String annotationName = annotation.annotationType().getName();
String abstractValidatorClassName = Validator.class.getSimpleName();
/**
* some convention over configuration
* convention:
* if your annotation is named "Min" and we know this abstract class is
* named "Validator", then your validator rule will have to be implemented
* in a file named "MinValidator" ("Min" + "Validator" joined/concatenated)
*
* Why are we doing this?
* if we have an annotation "Min", based on that annotation, this Framework
* can then find the matching validator rule in a file named "MinValidator".
* This static "validate" method uses Java Reflection to:
* - the current forEach iteration's annotation (find the name in String)
* - this abstract class name (in String)
* - concat them together, annotation name first
* - looks for a class matching the concatenated String
* > this class should extend abstract class "Validator"
* - create an instance of that class
* > (through it's constructor, retieved using Java Reflection)
* - calls its "applyRule" method (with appropriate arguments)
* > we know the instance of the class has the "applyRule" method
* > because this class extends abstract class "Validator"
* > and this abstract class "Validator" has an abstract "applyRule" method
*/
String validatorClassName = String.join("", annotationName, abstractValidatorClassName);
Class< ?> validatorClass;
try {
validatorClass = Class.forName(validatorClassName);
} catch (Exception exp) {
throw new ValidationException(
"Cannot find Validator subclass " + validatorClassName +
".class to validate targetted field "" + String.join(".", field.getDeclaringClass().getName(), field.getName()) +
"" annotated with @" + annotationName + ". Was such a subclass defined?"
);
}
if (validatorMap.get(validatorClassName) == null)
validatorMap.put(validatorClassName, validatorClass.getConstructor().newInstance(new Object[0]));
Object validatorInstance = validatorMap.get(validatorClassName);
field.setAccessible(true); // to access private field
Method method = validatorClass.getMethod(
APPLY_RULE_METHOD_NAME,
Annotation.class,
Object.class,
Class.class
);
try {
method.invoke(validatorInstance, annotation, field.get(model), field.getType());
} catch (InvocationTargetException ite) {
if (ite.getCause() instanceof ValidationException)
throw new ValidationException(
"Field [ " +
String.join(".", field.getDeclaringClass().getName(), field.getName()) +
" ]" + ite.getCause().getMessage()
);
}
}
}
}
/**
* finding fields from model Class, as well as fields from its superclass hierarchy
*/
public static List< Field> getInheritedDeclaredFields(Object model) throws Exception {
List< Field> fields = new ArrayList< Field>();
Class< ?> modelClass = model.getClass();
while (modelClass != null) {
fields.addAll(Arrays.asList(modelClass.getDeclaredFields()));
modelClass = modelClass.getSuperclass();
}
return fields;
}
private final static Set< Class< ?>> NUMBER_REFLECTED_PRIMITIVES;
static {
Set< Class< ?>> s = new HashSet< >();
s.add(byte.class);
s.add(short.class);
s.add(int.class);
s.add(long.class);
s.add(float.class);
s.add(double.class);
NUMBER_REFLECTED_PRIMITIVES = s;
}
public static boolean isReflectedAsNumber(Class< ?> type) {
return Number.class.isAssignableFrom(type) || NUMBER_REFLECTED_PRIMITIVES.contains(type);
}
}
CharCountValidator.java
import java.lang.reflect.*;
import java.lang.annotation.Annotation;
public class CharCountValidator extends Validator {
private static CharCount charCount;
public void applyRule(Annotation annotation, Object fieldValue, Class fieldType) throws Exception {
charCount = (CharCount) annotation;
/**
* developer/coder throws for potential annotating errors
*/
if (!fieldType.equals(String.class))
throw new ValidationException(" is not of type String; Annotation @CharCount can only be applied to fields of type String.");
if (charCount.min() < 0 || charCount.max() < 0)
throw new ValidationException(" Annotation @CharCount parameters cannot be less than zero.");
if (charCount.min() == 0 && charCount.max() == 0)
throw new ValidationException(" Annotation @CharCount parameters min() and max() cannot both be zero (their default values). At least one of these parameters has to set to an integer greater than zero.");
String fValue = fieldValue.toString();
int fieldLength = fValue.length();
boolean valid = true;
String message = "";
/**
* user relevant error messages
*/
if (charCount.min() > 0 && charCount.max() > 0) {
if (fieldLength < charCount.min() || fieldLength > charCount.max()) {
valid = false;
if (charCount.min() == charCount.max())
message = " character count (length) has to be exactly " + charCount.min();
else {
message = " character count (length) has to be between " + charCount.min() + " and " + charCount.max();
message += " inclusive. Field character count is " + fieldLength + ", containing "" + fValue + "".";
}
}
}
if (charCount.max() == 0) {
if (fieldLength < charCount.min()) {
valid = false;
message = " character count (length) has to be a minimum of " + charCount.min();
message += ". Field character count is " + fieldLength + ", containing "" + fValue + "".";
}
}
if (charCount.min() == 0) {
if (fieldLength > charCount.max()) {
valid = false;
message = " character count (length) has to be a maximum of " + charCount.max();
message += ". Field character count is " + fieldLength + ", containing "" + fValue + "".";
}
}
if (!valid) throw new ValidationException(message);
}
}
CreateDatabaseScript.sql
-- MySQL dump 10.13 Distrib 5.7.16, for Win64 (x86_64)
--- The first 3 lines will only work if running on local mysql
DROP DATABASE IF EXISTS `fridgedb`;
CREATE DATABASE `fridgedb`;
USE `fridgedb`;
-- Run from this line when running on latcs7 mysql
DROP TABLE IF EXISTS `grocery`;
DROP TABLE IF EXISTS `item`;
--
-- Table structure for table `item`
--
CREATE TABLE `item` (
`name` varchar(20) NOT NULL,
`expires` tinyint(4) NOT NULL DEFAULT '0',
PRIMARY KEY (`name`),
UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Dumping data for table `item`
--
LOCK TABLES `item` WRITE;
INSERT INTO `item` VALUES ('Beef',1),('Broccoli',1),('Cabbage',1),('Fish',1),('Ice Cream',0),('Gorgonzola',1),('Milk',0),('Oranges',0),('Paddle Pop',0),('Pecorino',1),('Tangerines',0),('Tofu',0);
UNLOCK TABLES;
--
-- Table structure for table `grocery`
--
CREATE TABLE `grocery` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`itemName` varchar(20) NOT NULL,
`date` varchar(10) DEFAULT NULL,
`quantity` int(11) DEFAULT NULL,
`section` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`),
KEY `itemName_idx` (`itemName`),
CONSTRAINT `fk_grocery_item` FOREIGN KEY (`itemName`) REFERENCES `item` (`name`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8;
--
-- Dumping data for table `grocery`
--
LOCK TABLES `grocery` WRITE;
INSERT INTO `grocery` VALUES (3,'Ice Cream','26/09/2019',1,'FREEZER'),(6,'Paddle Pop','26/09/2019',1,'FREEZER'),(19,'Beef','25/09/2019',1,'MEAT'), (20,'Pecorino','26/09/2019',2,'CRISPER'),(32,'Beef','26/09/2019',3,'MEAT');
UNLOCK TABLES;
-- Dump completed
FridgeDSC.java
import java.sql.*;
import java.util.*;
import java.io.File;
import java.io.PrintWriter;
import java.util.Scanner;
import java.time.LocalDate;
import java.time.Duration;
import java.time.format.DateTimeFormatter;
public class FridgeDSC {
// the date format we will be using across the application
public static final String DATE_FORMAT = "dd/MM/yyyy";
/*
FREEZER, // freezing cold
MEAT, // MEAT cold
COOLING, // general fridge area
CRISPER // veg and fruits section
note: Enums are implicitly public static final
*/
public enum SECTION {
FREEZER,
MEAT,
COOLING,
CRISPER
};
private Connection connection;
private Statement statement;
private PreparedStatement preparedStatement;
private String dbUserName;
private String dbPassword;
private String dbURL;
// TODO:
// in order to allow the DSC to be compatible with either
// - latcs7 MySQL server (Bundoora and Bendigo Campuses only)
// - your own MySQL server (or any other)
// The dbHost argument will include both the host and the database
// example:
// localhost:3306/fridgedb
// latcs7.cs.latrobe.edu.au:3306/12345678
//
// In tomcat this will come from web.xml
// In the testing methods in the main below they are in the constructor call CHANGE THIS.
public FridgeDSC(String dbHost, String dbUserName, String dbPassword) {
this.dbUserName = dbUserName;
this.dbPassword = dbPassword;
this.dbURL = "jdbc:mysql://" + dbHost;
}
public void connect() throws SQLException {
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(dbURL, dbUserName, dbPassword);
statement = connection.createStatement();
} catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
}
public void disconnect() throws SQLException {
if (preparedStatement != null) {
preparedStatement.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
}
public Item searchItem(String name) throws Exception {
String queryString = "SELECT * FROM item WHERE name = ?";
preparedStatement = connection.prepareStatement(queryString);
preparedStatement.setString(1, name);
ResultSet rs = preparedStatement.executeQuery();
Item item = null;
if (rs.next()) { // i.e. the item exists
boolean expires = rs.getBoolean(2);
item = new Item(name, expires);
}
return item;
}
public Grocery searchGrocery(int id) throws Exception {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(DATE_FORMAT);
String queryString = "SELECT * FROM grocery WHERE id = ?";
preparedStatement = connection.prepareStatement(queryString);
preparedStatement.setInt(1, id);
ResultSet rs = preparedStatement.executeQuery();
Grocery grocery = null;
if (rs.next()) { // i.e. the grocery exists
String itemName = rs.getString(2);
Item item = searchItem(itemName);
if (item == null) {
System.err.println("[WARNING] Item: '" + itemName + "'' does not exist!");
}
LocalDate date = LocalDate.parse(rs.getString(3), dtf);
int quantity = rs.getInt(4);
FridgeDSC.SECTION section = SECTION.valueOf(rs.getString(5));
grocery = new Grocery(id, item, date, quantity, section);
}
return grocery;
}
public List- getAllItems() throws Exception {
String queryString = "SELECT * FROM item";
ResultSet rs = statement.executeQuery(queryString);
List- items = new ArrayList
- ();
while (rs.next()) { // i.e. items exists
String name = rs.getString(1);
boolean expires = rs.getBoolean(2);
items.add(new Item(name, expires));
}
return items;
}
public List- getAllExpiredItems() throws Exception {
String queryString = "SELECT * FROM item where expires is true";
ResultSet rs = statement.executeQuery(queryString);
List- items = new ArrayList
- ();
while (rs.next()) { // i.e. items exists
String name = rs.getString(1);
boolean expires = rs.getBoolean(2);
items.add(new Item(name, expires));
}
return items;
}
public ListgetAllGroceries() throws Exception {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(DATE_FORMAT);
String queryString = "SELECT * FROM grocery";
ResultSet rs = statement.executeQuery(queryString);
Listgroceries = new ArrayList ();
while (rs.next()) { // i.e. groceries exists
int id = rs.getInt(1);
String itemName = rs.getString(2);
Item item = searchItem(itemName);
if (item == null) {
System.err.println("[WARNING] Item: '" + itemName + "'' does not exist!");
continue;
}
LocalDate date = LocalDate.parse(rs.getString(3), dtf);
int quantity = rs.getInt(4);
SECTION section = SECTION.valueOf(rs.getString(5));
groceries.add(new Grocery(id, item, date, quantity, section));
}
return groceries;
}
public ListgetAllGroceryExpiredItems() throws Exception {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(DATE_FORMAT);
String queryString = "select * from grocery,item where grocery.itemName=item.name AND item.expires=true";
ResultSet rs = statement.executeQuery(queryString);
Listgroceries = new ArrayList ();
while (rs.next()) { // i.e. groceries exists
int id = rs.getInt(1);
String itemName = rs.getString(2);
Item item = searchItem(itemName);
if (item == null) {
System.err.println("[WARNING] Item: '" + itemName + "'' does not exist!");
continue;
}
LocalDate date = LocalDate.parse(rs.getString(3), dtf);
int quantity = rs.getInt(4);
SECTION section = SECTION.valueOf(rs.getString(5));
groceries.add(new Grocery(id, item, date, quantity, section));
}
return groceries;
}
public int addGrocery(String name, int quantity, SECTION section) throws Exception {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(DATE_FORMAT);
LocalDate date = LocalDate.now();
String dateStr = date.format(dtf);
// NOTE: should we check if itemName (argument name) exists in item table?
// --> adding a groceries with a non-existing item name should through an exception
String command = "INSERT INTO grocery VALUES(?, ?, ?, ?, ?)";
preparedStatement = connection.prepareStatement(command);
preparedStatement.setInt(1, 0);
preparedStatement.setString(2, name);
preparedStatement.setString(3, dateStr);
preparedStatement.setInt(4, quantity);
preparedStatement.setString(5, section.toString());
preparedStatement.executeUpdate();
ResultSet rs = statement.executeQuery("SELECT LAST_INSERT_ID()");
rs.next();
int newId = rs.getInt(1);
return newId;
}
public Grocery useGrocery(int id) throws Exception {
Grocery g = searchGrocery(id);
if (g == null) {
return null;
}
if (g.getQuantity() <= 1) {
throw new UpdateNotAllowedException("There is only one: " + g.getItemName() + " (bought on " + g.getDateStr() + ") - use DELETE instead.");
}
String queryString
= "UPDATE grocery "
+ "SET quantity = quantity - 1 "
+ "WHERE quantity > 1 "
+ "AND id = " + id + ";";
if (statement.executeUpdate(queryString) > 0) {
return searchGrocery(id);
} else {
return null;
}
}
public int removeGrocery(int id) throws Exception {
String queryString = "SELECT COUNT(*) FROM grocery WHERE id = ?";
preparedStatement = connection.prepareStatement(queryString);
preparedStatement.setInt(1, id);
ResultSet rs = preparedStatement.executeQuery();
// are there any results
boolean pre = rs.next();
if (!pre) { // no, throw error
throw new RuntimeException("The grocery does not exist!");
}
// there are results, proceed with delete
return statement.executeUpdate("DELETE FROM grocery WHERE id = " + id);
}
// STATIC HELPERS -------------------------------------------------------
public static long calcDaysAgo(LocalDate date) {
return Math.abs(Duration.between(LocalDate.now().atStartOfDay(), date.atStartOfDay()).toDays());
}
public static String calcDaysAgoStr(LocalDate date) {
String formattedDaysAgo;
long diff = calcDaysAgo(date);
if (diff == 0) {
formattedDaysAgo = "today";
} else if (diff == 1) {
formattedDaysAgo = "yesterday";
} else {
formattedDaysAgo = diff + " days ago";
}
return formattedDaysAgo;
}
public static void main(String[] args) throws Exception {
// FridgeDSC dsc = new FridgeDSC("latcs7.cs.latrobe.edu.au:3306/12345678", "12345678", "j2Pth2f5GntPTFn9mmNk");
FridgeDSC dsc = new FridgeDSC("localhost:3306/fridgedb", "root", "");
try {
dsc.connect();
System.out.println(dsc.getAllGroceries());
System.out.println(dsc.removeGrocery(455));
System.out.println(dsc.useGrocery(455));
System.out.println(dsc.useGrocery(19));
} catch (Exception exp) {
exp.printStackTrace();
}
}
}
Item.java
public class Item {
// name is the unique id
private String name;
private boolean expires; // defaults to false
// constructor
public Item(String name, boolean expires) {
this.name = name;
this.expires = expires;
}
// constructor
public Item(String name) {
this(name, false);
}
public String getName() {
return this.name;
}
public boolean canExpire() {
return this.expires;
}
public String toString() {
return "[ name: " + this.name
+ ", expires: " + this.expires
+ " ]";
}
// To perform some quick tests
public static void main(String[] args) {
Item i1 = new Item("Milk", false);
System.out.println(i1);
Item i2 = new Item("Fish", true);
System.out.println(i2);
}
}
Max.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/* Define annotation interface Min
*/
@Retention(RetentionPolicy.RUNTIME)
// Process this annotation at runtime
@Target(ElementType.FIELD)
// This is an annotation on a field (attribute)
public @interface Max {
public double value();
public boolean inclusive() default true;
}
MaxValidator.java
import java.lang.reflect.*;
import java.lang.annotation.Annotation;
public class MaxValidator extends Validator {
private static Max max;
public void applyRule(Annotation annotation, Object fieldValue, Class< ?> fieldType) throws Exception {
/**
* developer/coder throws for potential annotating errors
*/
if (!isReflectedAsNumber(fieldType))
throw new ValidationException(" is not a primitive number type or a subclass of Number. Annotation @Max cannot be applied to non-number types.");
max = (Max) annotation;
double fValue = Double.parseDouble(fieldValue.toString());
boolean valid = max.inclusive() ? fValue < = max.value(): fValue < max.value();
if (!valid) {
String message = " must be greater than ";
String orEquals = max.inclusive() ? "(or equals to) " : "";
message += orEquals + max.value() + ".";
throw new ValidationException(message);
}
}
}
Min.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/* Define annotation interface Min
*/
@Retention(RetentionPolicy.RUNTIME)
// Process this annotation at runtime
@Target(ElementType.FIELD)
// This is an annotation on a field (attribute)
public @interface Min {
public double value();
public boolean inclusive() default true;
}
MinValidator.java
import java.lang.reflect.*;
import java.lang.annotation.Annotation;
public class MinValidator extends Validator {
private static Min min;
public void applyRule(Annotation annotation, Object fieldValue, Class< ?> fieldType) throws Exception {
/**
* developer/coder throws for potential annotating errors
*/
if (!isReflectedAsNumber(fieldType))
throw new ValidationException(" is not a primitive number type or a subclass of Number. Annotation @Min cannot be applied to non-number types.");
min = (Min) annotation;
double fValue = Double.parseDouble(fieldValue.toString());
boolean valid = min.inclusive() ? fValue >= min.value(): fValue > min.value();
if (!valid) {
String message = " must be greater than ";
String orEquals = min.inclusive() ? "(or equals to) " : "";
message += orEquals + min.value() + ".";
throw new ValidationException(message);
}
}
}
NotNull.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Marks the field as NotNull : a null value is not allowed.
*/
@Retention(RetentionPolicy.RUNTIME)
// Process this annotation at runtime
@Target(ElementType.FIELD)
// This is an annotation on a field (attribute)
public @interface NotNull {
}
NotNullValidator.java
import java.lang.reflect.*;
import java.lang.annotation.Annotation;
public class NotNullValidator extends Validator {
private static NotNull notNull;
public void applyRule(Annotation annotation, Object fieldValue, Class< ?> fieldType) throws Exception {
/**
* developer/coder throws for potential annotating errors
*/
if (isReflectedAsNumber(fieldType))
throw new ValidationException(" is a primitive number type or a subclass of Number. Annotation @NotNull for null check cannot be applied.");
notNull = (NotNull) annotation;
boolean valid = fieldValue != null;
if (!valid) {
String message = " must not be null.";
throw new ValidationException(message);
}
}
}
ResourceNotFoundException.java
public class ResourceNotFoundException extends Exception {
private static final long serialVersionUID = 1L;
public ResourceNotFoundException() {
super();
}
public ResourceNotFoundException(String message) {
super(message);
}
}
UpdateNotAllowedException
public class UpdateNotAllowedException extends Exception {
private static final long serialVersionUID = 1L;
public UpdateNotAllowedException() {
super();
}
public UpdateNotAllowedException(String message) {
super(message);
}
}
ValidationException.java
public class ValidationException extends Exception {
private static final long serialVersionUID = 1L;
public ValidationException() {
super();
}
public ValidationException(String message) {
super(message);
}
}