{title:'Object Tools', created:'9.0.0'}

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 Map Maps} and Java beans representing JSON objects.
- {@link 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.

##### Example:

| // 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.

##### Example:

| // 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.

##### Example:

| 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.

##### Example:

| 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.

##### Example:

| 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.

##### Example:

| 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.

##### Example:

| 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());