Streaming Data Access for BSON and JSON encoded documents
Boson is available through the Central Maven Repository. For SBT users, please add the following dependency in your build.sbt:
libraryDependencies += Not Yet
For Maven users, please add the following dependency in your pom.xml:
<dependency>
<groupId>not.yet</groupId>
<artifactId>not-yet</artifactId>
<version>NotYet</version>
</dependency>
A "Boson" is an object created when constructing an extractor/injector that encapsulates an encoded BSON in a Netty buffer and processes it according to a given expression, traversing the buffer only once.
Extraction requires a "BsonPath" expression (see Operators table for examples and syntax), an encoded BSON, an Higher-Order Function and a Synchrononization tool in case multiple extractions are to be performed. The Extractor instance is built only once and can be reused multiple times to extract from different encoded BSON.
//Encode Bson:
val validatedByteArray: Array[Byte] = bsonEvent.encode().array()
//BsonPath expression:
val expression: String = "..fridgeReadings.[1].fanVelocity"
//Synchronization tool:
val latch: CountDownLatch = new CountDownLatch(1)
//Simple Extractor:
val boson: Boson = Boson.extractor(expression, (in: BsValue) => {
// Use 'in' value, this is the value extracted.
latch.countDown()
})
//Trigger extraction with encoded Bson:
boson.go(validatedByteArray)
//Wait to complete extraction:
latch.await()
Injection requires a "BsonPath" expression (see Operators table for examples and syntax), an encoded BSON and an Higher-Order Function. The returned result is a CompletableFuture[Array[Byte]]. The Injector instance is built only once and can be reused to inject different encoded BSON.
//Encode Bson:
val validBsonArray: Array[Byte] = bsonEvent.encode().array()
//BsonPath expression:
val expression: String = "..Store..name"
//Simple Injector:
val boson: Boson = Boson.injector(expression, (in: String) => "newName")
//Trigger injection with encoded Bson:
val result: Array[Byte] = boson.go(validBsonArray).join()
Fusion requires a Boson Extractor and a Boson Injector or two Boson of the same type. The order in which fuse is applied is left to the discretion of the user. This fusion is executed sequentially at the moment.
//First step is to construct both Boson.injector and Boson.extractor by providing the necessary arguments.
val validatedByteArray: Array[Byte] = bsonEvent.encode().array()
val expression = "name"
val ext: Boson = Boson.extractor(expression, (in: BsValue) => {
// Use 'in' value, this is the value extracted.
})
val inj: Boson = Boson.injector(expression, (in: String) => "newName")
//Then call fuse() on injector or extractor, it returns a new BosonObject.
val fused: Boson = ext.fuse(inj)
//Finally call go() providing the byte array or a ByteBuffer on the new Boson object.
val finalFuture: Array[Byte] = fused.go(validatedByteArray).join()
A "Joson" is an object created when constructing an extractor/injector that encapsulates a JSON String, encoding it as a BSON in a Netty buffer, and then processes it according to a given expression, traversing the buffer only once.
Extraction requires a "BsonPath" expression (see Operators table for examples and syntax), a JSON String, an Higher-Order Function and a Synchrononization tool in case multiple extractions are to be performed. The Extractor instance is built only once and can be reused multiple times to extract from different JSON Strings.
//BsonPath expression:
val expression: String = "..Book[1]"
//Json String:
val json = “““{
"Store":{
"Book":[
{
"Price":10
},
{
"Price":20
}
],
"Hat":[
{
"Price":30
},
{
"Price":40
}
]
}
}”””
//Synchronization tool:
val latch: CountDownLatch = new CountDownLatch(1)
//Simple Extractor:
val joson: Joson = Joson.extractor(expression, (in: BsValue) => {
// Use 'in' value, this is the value extracted.
latch.countDown()
})
//Trigger extraction with Json:
val result: String = joson.go(json).join()
//Wait to complete extraction:
latch.await()
Injection requires a "BsonPath" expression (see Operators table for examples and syntax), a JSON String and an Higher-Order Function. The returned result is a CompletableFuture[Array[Byte]]. The Injector instance is built only once and can be reused to inject different JSON Strings.
//BsonPath expression:
val expression: String = "..Book[1]"
//Json String:
val json = “““{
"Store":{
"Book":[
{
"Price":10
},
{
"Price":20
}
],
"Hat":[
{
"Price":30
},
{
"Price":40
}
]
}
}”””
//Simple Injector:
val joson: Joson = Joson.injector(expression, (in: Map[String, Object]) => {
in.+(("Title", "Scala"))
})
//Trigger injection with Json:
val result: String = joson.go(json).join()
For Maven users, please add the following dependency in your pom.xml:
<dependency>
<groupId>not.yet</groupId>
<artifactId>not-yet</artifactId>
<version>NotYet</version>
</dependency>
A "Boson" is an object created when constructing an extractor/injector that encapsulates an encoded BSON in a Netty buffer and processes it according to a given expression, traversing the buffer only once.
Extraction requires a "BsonPath" expression (see Operators table for examples and syntax), an encoded BSON, an Higher-Order Function and a Synchrononization tool in case multiple extractions are to be performed. The Extractor instance is built only once and can be reused multiple times to extract from different encoded BSON.
//Encode Bson:
byte[] validatedByteArray = bsonEvent.encode().array();
//BsonPath expression:
String expression = "..Store..SpecialEditions[@Extra]";
//Synchronization tool:
CountDownLatch latch = new CountDownLatch(1);
//Simple Extractor:
Boson boson = Boson.extractor(expression, obj-> {
// Use 'obj' value, this is the value extracted.
latch.countDown();
});
//Trigger extraction with encoded Bson:
boson.go(validatedByteArray);
//Wait to complete extraction:
latch.await();
Injection requires a "BsonPath" expression (see Operators table for examples and syntax), an encoded BSON and an Higher-Order Function. The returned result is a CompletableFuture<byte[]>. The Injector instance is built only once and can be reused to inject different encoded BSON.
//Encode Bson:
byte[] validatedByteArray = bsonEvent.encode().array();
//BsonPath expression:
String expression = "..Store.[2 until 4]";
//Simple Injector:
Boson boson = Boson.injector(expression, (Map<String, Object> in) -> {
in.put("WHAT", 10);
return in;
});
//Trigger injection with encoded Bson:
byte[] result = boson.go(validatedByteArray).join();
Fusion requires a Boson Extractor and a Boson Injector or two Boson of the same type. The order in which fuse is applied is left to the discretion of the user. This fusion is executed sequentially at the moment.
//First step is to construct both Boson.injector and Boson.extractor by providing the necessary arguments.
final byte[] validatedByteArray = bsonEvent.encode().array();
final String expression = "name";
final Boson ext = Boson.extractor(expression, (in: BsValue) -> {
// Use 'in' value, this is the value extracted.
});
final Boson inj = Boson.injector(expression, (in: String) -> "newName");
//Then call fuse() on injector or extractor, it returns a new BosonObject.
final Boson fused = ext.fuse(inj);
//Finally call go() providing the byte array or a ByteBuffer on the new Boson object.
final byte[] finalFuture = fused.go(validatedByteArray).join();
A "Joson" is an object created when constructing an extractor/injector that encapsulates a JSON String, encoding it as a BSON in a Netty buffer, and then processes it according to a given expression, traversing the buffer only once.
Extraction requires a "BsonPath" expression (see Operators table for examples and syntax), a JSON String, an Higher-Order Function and a Synchrononization tool in case multiple extractions are to be performed. The Extractor instance is built only once and can be reused multiple times to extract from different JSON Strings.
//BsonPath expression:
String expression = "..Book[1]";
//Json String:
String jsonStr = "{\"Store\":{\"Book\":[{\"Price\":10},{\"Price\":20}],\"Hat\":[{\"Price\":30},{\"Price\":40}]}}"
//Synchronization tool:
CountDownLatch latch = new CountDownLatch(1);
//Simple Extractor:
Joson joson = Joson.extractor(expression, obj-> {
// Use 'obj' value, this is the value extracted.
latch.countDown();
});
//Trigger extraction with Json:
joson.go(jsonStr);
//Wait to complete extraction:
latch.await()
Injection requires a "BsonPath" expression (see Operators table for examples and syntax), a JSON String and a Function. The returned result is a CompletableFuture<byte[]>. The Injector instance is built only once and can be reused to inject different JSON Strings.
//BsonPath expression:
String expression = "..Book[1]";
//Json String:
String jsonStr = "{\"Store\":{\"Book\":[{\"Price\":10},{\"Price\":20}],\"Hat\":[{\"Price\":30},{\"Price\":40}]}}"
//Simple Injector:
Joson joson = Joson.injector(expression, (Map<String, Object> in) -> {
in.put("WHAT", 10);
return in;
});
//Trigger injection with Json:
String result = joson.go(jsonStr).join();
BsonPath expressions targets a BSON structure with the same logic as JsonPath expressions target JSON structure and XPath targeted a XML document. Unlike JsonPath there is no reference of a "root member object", instead if you want to specify a path starting from the root, the expression must begin with a dot (.key
).
BsonPath expressions use the dot-notation: key1.key2[0].key3
.
Expressions whose path doesn't necessarily start from the root can be expressed in two ways:
- No dot -
key
- Two dots -
..key
Operator | Description |
---|---|
. |
Child. |
.. |
Deep scan. Available anywhere a name is required. |
@ |
Current node. |
[<number> ((to,until) <number>)] |
Array index or indexes. |
[@<key>] |
Filter expression. |
* |
Wildcard. Available anywhere a name is required. |
Given the json
{
"Store":{
"Book":[
{
"Title":"Java",
"Price":15.5,
"SpecialEditions":[
{
"Title":"JavaMachine",
"Price":39
}
]
},
{
"Title":"Scala",
"Pri":21.5,
"SpecialEditions":[
{
"Title":"ScalaMachine",
"Price":40
}
]
},
{
"Title":"C++",
"Price":12.6,
"SpecialEditions":[
{
"Title":"C++Machine",
"Price":38
}
]
}
],
"Hat":[
{
"Price":48,
"Color":"Red"
},
{
"Price":35,
"Color":"White"
},
{
"Price":38,
"Color":"Blue"
}
]
}
}
BsonPath | JsonPath |
---|---|
.Store |
$.Store |
.Store.Book[@Price] |
$.Store.Book[?(@.Price)] |
Book[@Price]..Title |
$..Book[?(@.Price)]..Title |
Book[1] |
$..Book[1] |
Book[0 to end]..Price |
$..Book[:]..Price |
Book[0 to end].*..Title |
$..Book[:].*..Title |
.* |
$.* |
Book.*.[0 to end] |
$..Book.*.[:] |
.Store..Book[1 until end]..SpecialEditions[@Price] |
$.Store..Book[1:1]..SpecialEditions[?(@.Price)] |
Bo*k , *ok or Bo* |
Non existent. |
*ok[@Pri*]..SpecialEd*.Price |
Non existent. |
Note: JsonPath doesn't support the halfkey (B*ok
) as well as the range until end (1 until end
).