Object Tools
The org.apache.juneau.objecttools package defines convenience utility classes for accessing and manipulating POJOs.
It consists of the following classes:
ObjectRest
The 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:
Leaves of the tree can be any type of object.
- Use get() to retrieve an element from a JSON tree.
- Use put() to create (or overwrite) an element in a JSON tree.
- Use post() to add an element to a list in a JSON tree.
- Use 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 @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 Traversable REST response converter.
ObjectSearcher
The 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 result = searcher.run(arrayOfBeans, "foo=X,bar=Y");
The tool can be used against the following data types:
- Arrays/
Collections
ofMaps
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:
The 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 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 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 - 2013-06-30"
- Closed ranges
This class is used in the Queryable REST response converter.
ObjectSorter
The 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 result = sorter.run(arrayOfBeans, "foo,bar-");
The tool can be used against the following data types:
- Arrays/
Collections
ofMaps
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 Queryable REST response converter.
ObjectViewer
The 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 result = viewer.run(arrayOfBeans, "foo,bar");
The tool can be used against the following data types:
- Arrays/
Collections
ofMaps
or beans. - Singular maps or beans.
This class is used in the Queryable REST response converter.
ObjectPaginator
The 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 result = paginator.run(arrayOfBeans, 100, 10);
The tool can be used against the following data types:
- Arrays/
Collections
ofMaps
or beans.
This class is used in the Queryable REST response converter.
ObjectIntrospector
The ObjectIntrospector class is used to invoke
methods on 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 Introspectable REST response converter.
This is an extremely powerful but potentially dangerous tool. Use wisely.
ObjectMerger
The 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());