The {@link oaj.objecttools} package defines convenience utility classes for accessing
and manipulating POJOs. It consists of the following classes:
- {@link oaj.objecttools.ObjectRest}
- {@link oaj.objecttools.ObjectSearcher}
- {@link oaj.objecttools.ObjectSorter}
- {@link oaj.objecttools.ObjectViewer}
- {@link oaj.objecttools.ObjectPaginator}
- {@link oaj.objecttools.ObjectIntrospector}
- {@link oaj.objecttools.ObjectMerger}
ObjectRest
The {@link oaj.objecttools.ObjectRest} class provides the ability to perform standard REST operations (GET, PUT, POST, DELETE) against nodes in a POJO model.
Nodes in the POJO model are addressed using URLs.
A POJO model is defined as a tree model where nodes consist of consisting of the following:
-
{@link java.util.Map Maps} and Java beans representing JSON objects.
-
{@link java.util.Collection Collections} and arrays representing JSON arrays.
-
Java beans.
Leaves of the tree can be any type of object.
Use {@link oaj.objecttools.ObjectRest#get(String) get()} to retrieve an element from a JSON tree.
Use {@link oaj.objecttools.ObjectRest#put(String,Object) put()} to create (or overwrite) an element in a JSON tree.
Use {@link oaj.objecttools.ObjectRest#post(String,Object) post()} to add an element to a list in a JSON tree.
Use {@link oaj.objecttools.ObjectRest#delete(String) delete()} to remove an element from a JSON tree.
| // Construct an unstructured POJO model
| JsonMap map = JsonMap.ofJson(""
| + "{"
| + " name:'John Smith', "
| + " address:{ "
| + " streetAddress:'21 2nd Street', "
| + " city:'New York', "
| + " state:'NY', "
| + " postalCode:10021 "
| + " }, "
| + " phoneNumbers:[ "
| + " '212 555-1111', "
| + " '212 555-2222' "
| + " ], "
| + " additionalInfo:null, "
| + " remote:false, "
| + " height:62.4, "
| + " 'fico score':' > 640' "
| + "} "
| );
|
| // Wrap Map inside an ObjectRest object
| ObjectRest johnSmith = ObjectRest.create(map);
|
| // Get a simple value at the top level
| // "John Smith"
| String name = johnSmith.getString("name");
|
| // Change a simple value at the top level
| johnSmith.put("name", "The late John Smith");
|
| // Get a simple value at a deep level
| // "21 2nd Street"
| String streetAddress = johnSmith.getString("address/streetAddress");
|
| // Set a simple value at a deep level
| johnSmith.put("address/streetAddress", "101 Cemetery Way");
|
| // Get entries in a list
| // "212 555-1111"
| String firstPhoneNumber = johnSmith.getString("phoneNumbers/0");
|
| // Add entries to a list
| johnSmith.post("phoneNumbers", "212 555-3333");
|
| // Delete entries from a model
| johnSmith.delete("fico score");
|
| // Add entirely new structures to the tree
| JsonMap medicalInfo = JsonMap.ofJson(""
| + "{"
| + " currentStatus: 'deceased',"
| + " health: 'non-existent',"
| + " creditWorthiness: 'not good'"
| + "}"
| );
| johnSmith.put("additionalInfo/medicalInfo", medicalInfo);
In the special case of collections/arrays of maps/beans, a special XPath-like selector notation can be used in lieu
of index numbers on GET requests to return a map/bean with a specified attribute value.
The syntax is {@code @attr=val}, where attr is the attribute name on the child map, and val is the matching value.
| // Get map/bean with name attribute value of 'foo' from a list of items
| Map map = objectRest.getMap("/items/@name=foo");
- This class is used in the {@link oajr.converter.Traversable} REST response converter.
ObjectSearcher
The {@link oaj.objecttools.ObjectSearcher} class is designed to provide searches across arrays and collections of maps or beans.
It allows you to quickly filter beans and maps using simple yet sophisticated search arguments.
| MyBean[] arrayOfBeans = ...;
| ObjectSearcher searcher = ObjectSearcher.create();
|
| // Returns a list of beans whose 'foo' property is 'X' and 'bar' property is 'Y'.
| List<MyBean> result = searcher.run(arrayOfBeans, "foo=X,bar=Y");
The tool can be used against the following data types:
- Arrays/collections of maps or beans.
The default searcher is configured with the following matcher factories that provides the capabilities of matching
against various data types. This list is extensible:
- {@link oaj.objecttools.StringMatcherFactory}
- {@link oaj.objecttools.NumberMatcherFactory}
- {@link oaj.objecttools.TimeMatcherFactory}
The {@link oaj.objecttools.StringMatcherFactory} class provides searching based on the following patterns:
- "property=foo" - Simple full word match
- "property=fo*", "property=?ar" - Meta-character matching
- "property=foo bar"(implicit), "property=^foo ^bar"(explicit) - Multiple OR'ed patterns
- "property=+fo* +*ar" - Multiple AND'ed patterns
- "property=fo* -bar" - Negative patterns
- "property='foo bar'" - Patterns with whitespace
- "property=foo\\'bar" - Patterns with single-quotes
- "property=/foo\\s+bar" - Regular expression match
The {@link oaj.objecttools.NumberMatcherFactory} class provides searching based on the following patterns:
- "property=1" - A single number
- "property=1 2" - Multiple OR'ed numbers
- "property=-1 -2" - Multiple OR'ed negative numbers
- "property=1-2","property=-2--1" - A range of numbers (whitespace ignored)
- "property=1-2 4-5" - Multiple OR'ed ranges
- "property=<1","property=<=1","property=>1","property=>=1" - Open-ended ranges
- "property=!1","property=!1-2" - Negation
The {@link oaj.objecttools.TimeMatcherFactory} class provides searching based on the following patterns:
- "property=2011" - A single year
- "property=2011 2013 2015" - Multiple years
- "property=2011-01" - A single month
- "property=2011-01-01" - A single day
- "property=2011-01-01T12" - A single hour
- "property=2011-01-01T12:30" - A single minute
- "property=2011-01-01T12:30:45" - A single second
- "property=>2011","property=>=2011","property=<2011","property=<=2011" - Open-ended ranges
- "property=>2011","property=>=2011","property=<2011","property=<=2011" - Open-ended ranges
- "property=2011 - 2013-06-30" - Closed ranges
- This class is used in the {@link oajr.converter.Queryable} REST response converter.
ObjectSorter
The {@link oaj.objecttools.ObjectSorter} class is designed to sort arrays and collections of maps or beans.
| MyBean[] arrayOfBeans = ...;
| ObjectSorter sorter = ObjectSorter.create();
|
| // Returns a list of beans sorted accordingly.
| List<MyBean> result = sorter.run(arrayOfBeans, "foo,bar-");
The tool can be used against the following data types:
- Arrays/collections of maps or beans.
The arguments are a simple comma-delimited list of property names optionally suffixed with '+' and '-' to
denote ascending/descending order.
- This class is used in the {@link oajr.converter.Queryable} REST response converter.
ObjectViewer
The {@link oaj.objecttools.ObjectViewer} class is designed to extract properties from collections of maps or beans.
| MyBean[] arrayOfBeans = ...;
| ObjectViewer viewer = ObjectViewer.create();
| // Returns the 'foo' and 'bar' properties extracted into a list of maps.
| List<Map> result = viewer.run(arrayOfBeans, "foo,bar");
The tool can be used against the following data types:
- Arrays/collections of maps or beans.
- Singular maps or beans.
- This class is used in the {@link oajr.converter.Queryable} REST response converter.
ObjectPaginator
The {@link oaj.objecttools.ObjectPaginator} class is designed to extract sublists from arrays/collections of maps or beans.
| MyBean[] arrayOfBeans = ...;
| ObjectPaginator paginator = ObjectPaginator.create();
|
| // Returns all rows from 100 to 110.
| List<MyBean> result = paginator.run(arrayOfBeans, 100, 10);
The tool can be used against the following data types:
- Arrays/collections of maps or beans.
- This class is used in the {@link oajr.converter.Queryable} REST response converter.
ObjectIntrospector
The {@link oaj.objecttools.ObjectIntrospector} class is used to invoke methods on {@code Objects} using arguments in serialized form.
| String string1 = "foobar";
| String string2 = ObjectIntrospector
| .create(string)
| .invoke(String.class, "substring(int,int)", "[3,6]"); // "bar"
The arguments passed to the identified method are POJOs serialized in JSON format. Arbitrarily complex arguments can be passed
in as arguments.
- This class is used in the {@link oajr.converter.Introspectable} REST response converter.
- This is an extremely powerful but potentially dangerous tool. Use wisely.
ObjectMerger
The {@link oaj.objecttools.ObjectMerger} class is used for merging POJOs behind a single interface.
This is particularly useful in cases where you want to define beans with 'default' values.
For example, given the following bean classes:
| public interface IA {
| String getX();
| void setX(String x);
| }
|
| public class A implements IA {
| private String x;
|
| public A(String x) {
| this.x = x;
| }
|
| public String getX() {
| return x;
| }
|
| public void setX(String x) {
| this.x = x;
| }
| }
The getters will be called in order until the first non-null value is returned:
| merge = ObjectMerger.merger(IA.class, new A("1"), new A("2"));
| assertEquals("1", merge.getX());
|
| merge = ObjectMerger.merger(IA.class, new A(null), new A("2"));
| assertEquals("2", merge.getX());
|
| merge = ObjectMerger.merger(IA.class, new A(null), new A(null));
| assertEquals(null, merge.getX());