A java framework using typed JSON for looseless communication of composed objects by one generic endpoint. Functionality is provided by special call objects with a generic execute method. Predefined generic calls for files, JSON, Excel, CSV, databases or templates. Compared with todays RPC its a "Remote Object Call" (ROC) architecture.
APACHE-2.0 License
elasticobjects.org provide a detailed documentation with interactive examples build by template calls. The sources you find in example-springboot.
Elastic Objects is a tiny layer offering path access methods to any java object tree.
With the configuration key embedded in json the serialization/deserialization allows typesafe communication between computers without endpoints or web frameworks. Embedded in arbitrary text it could initiate complex workflows or compose complex text.
The core has actually no dependencies beside Log4j and is rather small with a jar size of approximately 90 KB.
<dependency>
<groupId>org.fluentcodes.projects.elasticobjects</groupId>
<artifactId>elastic-objects</artifactId>
<version>0.9.4</version>
</dependency>
Some get and set operations.
EoRoot root = EoRoot.ofValue(CONFIG_MAPS, new AnObject());
EOInterfaceScalar child = root.set("test", "myAnObject", "myString");
assertEquals("test", root.get("myAnObject", "myString"));
assertEquals("test", child.get());
EoRoot root = EoRoot.ofValue(CONFIG_MAPS, new AnObject());
root.set("test", "myAnObject", "myString");
AnObject anObject = (AnObject) root.get();
assertEquals("test", anObject.getMyAnObject().getMyString());
For all accessors one can use a path string with a "/" delimiter like in a file system. Again we set the value test in the fields ≡AnObject and ≡myString.
EoRoot root = EoRoot.ofValue(CONFIG_MAPS, new AnObject());
EOInterfaceScalar child = root.set("test", "myAnObject/myString");
assertEquals("test", root.get("myAnObject/myString"));
assertEquals("test", child.get());
One can remove a branch from the object tree in a path way.
EoRoot root = EoRoot.ofValue(CONFIG_MAPS, new AnObject());
EOInterfaceScalar child = root.set("test", "myAnObject/myString");
EO parent = child.remove();
assertFalse(parent.hasEo("myString"));
AnObject parentObject = (AnObject) parent.get();
assertNull(parentObject.getMyString());
The field configuration ≡myString has a max size of 20. It will be checked when setting a value. In this example the value test01234567890123456789 has the length 24 and produce an exception.
EoRoot root = EoRoot.ofClass(CONFIG_MAPS, AnObject.class);
assertEquals(AnObject.class, root.getModelClass());
Assertions.assertThatThrownBy(
()->{root.set("test01234567890123456789", "myString");})
.isInstanceOf(EoException.class)
.hasMessageContaining("Problem creating child at '/' with key 'myString' with value 'test01234567890123456789' with message String value for field 'test01234567890123456789' has size 24 bigger than max length 20.");
Interactive example: https://www.elasticobjects.org/examples/AnObjectTooLong.html.
Here the previous example with "AnObjectMap":
EoRoot root = EoRoot.ofClassName(CONFIG_MAPS, "AnObjectMap");
assertEquals(LinkedHashMap.class.getSimpleName(), root.get().getClass().getSimpleName());
Assertions.assertThatThrownBy(
()->{root.set("test01234567890123456789", "myString");})
.isInstanceOf(EoException.class)
.hasMessageContaining("Problem creating child at '/' with key 'myString' with value 'test01234567890123456789' with message String value for field 'test01234567890123456789' has size 24 bigger than max length 20.");
Interactive example: https://www.elasticobjects.org/examples/AnObjectMapTooLong.html.
When field definition are set, also names will be checked:
EoRoot root = EoRoot.ofClassName(CONFIG_MAPS, "AnObjectMap");
Assertions.assertThatThrownBy(
()->{root.set("test", "notValid");})
.isInstanceOf(EoException.class)
.hasMessageContaining("Problem creating child at '/' with key 'notValid' with value 'test' with message No field defined for 'notValid'.");
Interactive example: https://www.elasticobjects.org/examples/AnObjectMapFieldNotExists.html.
The default json representation contains keys of the model configuration ≡AnObject:
EoRoot root = EoRoot.ofValue(CONFIG_MAPS, new AnObject());
EOInterfaceScalar child = root.set("test", "myAnObject", "myString");
assertEquals("{\n" +
" \"_rootmodel\": \"AnObject\",\n" +
" \"(AnObject)myAnObject\": {\n" +
" \"myString\": \"test\"\n" +
" }\n" +
"}", root.toJson());
This typed json will mapped to the appropriate object class when deserialized:
EoRoot root = EoRoot.ofValue(CONFIG_MAPS, new AnObject());
root.set("test", "myAnObject", "myString");
String json = root.toJson();
EoRoot rootFromJson = EoRoot.ofValue(CONFIG_MAPS, json);
assertEquals(AnObject.class, rootFromJson.get().getClass());
AnObject myAnObject = (AnObject)rootFromJson.get();
assertEquals("test", myAnObject.getMyAnObject().getMyString());
Interactive example: https://www.elasticobjects.org/examples/AnObjectTyped.html.
When a java object is mapped to EO the underlying object is a clone with the same structure and leaf values.
final AnObject anObject = new AnObject();
anObject.setMyString("value1");
final EoRoot rootMap = EoRoot.ofValue(CONFIG_MAPS, anObject);
final AnObject cloned = (AnObject) rootMap.get();
assertNotEquals(anObject, cloned);
assertEquals(anObject.getMyString(), cloned.getMyString());
One can easily transform an object to another type, when the target object has the same fields. The following example creates a Map from AnObject:
final AnObject anObject = new AnObject();
anObject.setMyString("value2");
final EoRoot rootMap = EoRoot.ofClass(CONFIG_MAPS, anObject, Map.class);
final Map transformed = (Map) rootMap.get();
assertEquals(anObject.getMyString(), transformed.get("myString"));
Every field key starting with underscore will not be mapped to the parent object.
final String json = "{\"myString\":\"test\", \"_comment\":\"FieldNames with underscore will not set in parent object.\"}";
final EoRoot root = EoRoot.ofClass(CONFIG_MAPS, json, AnObject.class);
assertEquals("FieldNames with underscore will not set in parent object.", root.get("_comment"));
assertEquals("{\n" +
" \"myString\": \"test\"\n" +
"}", root.toJson(JSONSerializationType.STANDARD));
Interactive example: https://www.elasticobjects.org/examples/Comment.html.
The calls module with a jar size of about 150 KB offers some basic calls also using configurations with a role permission concept for files and directories simple csv or templates.
<dependency>
<groupId>org.fluentcodes.projects.elasticobjects</groupId>
<artifactId>eo-calls</artifactId>
<version>0.9.2</version>
</dependency>
mvn repository
final Call call = new SinusValueCall();
EoRoot root = EoRoot.ofValue(CONFIG_MAPS, new HashMap());
EOInterfaceScalar child = root.set(2.1, "squareDegree");
assertEquals(2.1, child.get());
assertEquals(Double.valueOf(0.8632093666488737), call.execute(child));
This call could be also embedded in some arbitrary json using the ≡sourcePath as input. The result will stored to the ≡targetPath "sinusValue".
EoRoot root = EoRoot.ofValue(CONFIG_MAPS, "{\n" +
" \"(Double)squareDegree\":1,\n" +
" \"(SinusValueCall)sinusValue\": {\n" +
" \"sourcePath\": \"/squareDegree\"\n" +
" }\n" +
"}");
root.execute();
assertEquals("{\n" +
" \"squareDegree\": 1.0,\n" +
" \"sinusValue\": 0.8414709848078965\n" +
"}", root.toJson(JSONSerializationType.STANDARD));
Interactive example: https://www.elasticobjects.org/examples/SinusValueCall.html.
This json will be interpreted in an arbitrary text file via template call with the "@{...}" pattern. Here the target _asString will return the result to the template instead of setting the target in json.
EoRoot root = EoRoot.of(CONFIG_MAPS);
String template = "START - @{\n" +
" \"(Double)source\":1,\n" +
" \"(SinusValueCall)_asString\": {\n" +
" \"sourcePath\": \"/source\"\n" +
" }\n" +
"}. - END";
Call call = new TemplateCall(template);
assertEquals("START -0.8414709848078965 - END", call.execute(root));
Interactive example: https://www.elasticobjects.org/examples/SinusValueCallTemplate.html.
Calls could be included in an attribute and command form. This will be demonstrated by the following examples:
http://localhost:8080/examples/FileCall.html http://localhost:8080/examples/JsonCall.html
Interactive Examples: http://localhost:8080/examples/TemplateExamples.html
eo-csv offers calls and configurations for reading and writing csv files using OpenCsv.
<dependency>
<groupId>org.fluentcodes.projects.elasticobjects</groupId>
<artifactId>eo-csv</artifactId>
<version>0.9.4</version>
</dependency>
Interactive examples: http://localhost:8080/examples/ListCall.html
eo-db is experimental providing the execution of sql configurations as list or as query.
<dependency>
<groupId>org.fluentcodes.projects.elasticobjects</groupId>
<artifactId>eo-db</artifactId>
<version>0.9.4</version>
</dependency>
Interactive examples: https://www.elasticobjects.org/examples/DbCall.html.
eo-xlsx offers calls and configurations for reading and writing xlsx files using Apache POI.
<dependency>
<groupId>org.fluentcodes.projects.elasticobjects</groupId>
<artifactId>eo-xlsx</artifactId>
<version>0.9.4</version>
</dependency>
Interactive examples: http://localhost:8080/examples/ExcelCall.html
elastic-objects-test provide tests for the elastic-objects module. The main package providing test helper and test objects to other modules.
Since it has just test purposes there is actual no package on mvn central.
examples-springboot are the sources for the spring boot web example on http://www.elasticobjects.org.
Since it has just demo purposes there is actual no package on mvn central.
For the access to the embedded java objects EO is provided by preloaded model configurations in JSON.
The project has now version 0.9.4.
As a tool for creating and manipulating java objects it offers a lot of benefits.
For productive use in a flexible microservice architecture it's good enough for a proof of concept.