Pretty print for a groovy ConfigObject? - java

I have this groovy program that creates a groovy configuration file, using a ConfigObject. Once the ConfigObject is set up, it is written to a file using:
myFile.withWriter {writer -> myConfigObject.writeTo(writer)}
This results in each property of the ConfigObject being written on a single line. So for instance a map will be printed as:
graphs=[["type":"std", "host":"localhost", "name":"cpurawlinux"], ["type":"std", "host":"localhost", "name":"memory"], ["type":"std", "host":"localhost", "name":"udp"] ... ]
which is quite unreadable if someone has to take a look at it.
Is there a way to get a more friendly output? Something like that would be great:
graphs=[
["type":"std", "host":"localhost", "name":"cpurawlinux"],
["type":"std", "host":"localhost", "name":"memory"],
["type":"std", "host":"localhost", "name":"udp"]
...
]
I know I could create my own writeTo, but isn't there already something in Groovy for that?

Unfortunately, you'll need to write your own writeTo as you say.
If you have a config file with structure like:
graphs {
a=["type":"std", "host":"localhost", "name":"cpurawlinux"]
b=["type":"std", "host":"localhost", "name":"memory"]
}
Then writeTo will write it out with structure, but if your config file is just a big old list of things, it will write it out as a big old list

if it helps anyone, i had the same question and wrote this...not pretty (ha), but works:
def prettyPrint(properties, level=1, stringBuilder = new StringBuilder()) {
return properties.inject(stringBuilder) { sb, name, value ->
sb.append("\n").append("\t" * level).append(name)
if (!(value instanceof Map) && !(value instanceof List)) {
return sb.append("=").append(value)
} else {
return prettyPrint(properties.getProperty(name), level+1, sb)
}
}
}

Based on mike's answer above:
def prettyPrint
prettyPrint = {obj, level = 0, sb = new StringBuilder() ->
def indent = { lev -> sb.append(" " * lev) }
if(obj instanceof Map){
sb.append("{\n")
obj.each{ name, value ->
if(name.contains('.')) return // skip keys like "a.b.c", which are redundant
indent(level+1).append(name)
(value instanceof Map) ? sb.append(" ") : sb.append(" = ")
prettyPrint(value, level+1, sb)
sb.append("\n")
}
indent(level).append("}")
}
else if(obj instanceof List){
sb.append("[\n")
obj.each{ value ->
indent(level+1)
prettyPrint(value, level+1, sb).append(",")
sb.append("\n")
}
indent(level).append("]")
}
else if(obj instanceof String){
sb.append('"').append(obj).append('"')
}
else {
sb.append(obj)
}
}
For an input like:
{
grails {
scaffolding {
templates.domainSuffix = "Instance"
}
enable {
native2ascii = true
blah = [ 1, 2, 3 ]
}
mime.disable.accept.header.userAgents = [ "WebKit", "Presto", "Trident" ]
}
}
Produces:
{
grails {
scaffolding {
templates {
domainSuffix = "Instance"
}
}
enable {
native2ascii = true
blah = [
1,
2,
3,
]
}
mime {
disable {
accept {
header {
userAgents = [
"WebKit",
"Presto",
"Trident",
]
}
}
}
}
}
}

Related

Apache Camel Reducing Number though each Split Iteration

I have a directory of three files in the body of a Camel exchange, and I'm going to iterate through those 3 files using a Split. What I would like to do, is for each iteration, update a property with the total of all files (3 for this example) minus the current iteration. So at the some point, the goal is to have a property set to 1, so on another part of the code I can do logic based on this. I've tried a couple of different approaches but failed, and here I am. Here's a snippet of something I tried (simplified):
`private void test() {
from("timer:test?fixedRate=true&period=10000")
.process(exchange -> {
Path pathD = FileSystems.getDefault().getPath("Lmao").toAbsolutePath();
File folder = new File(pathD.toString());
String[] fileList = folder.list();
if (fileList != null) {
exchange.setProperty("PROPERTY", fileList.length);
}
exchange.getIn().setBody(fileList);
})
.split(body(), new AggregationStrategy() {
#Override
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
if (oldExchange == null) {
Integer iterationsLeft = newExchange.getProperty("PROPERTY", Integer.class);
Integer iterationsLeftMinusOne = iterationsLeft - 1;
newExchange.setProperty("PROPERTY", iterationsLeftMinusOne);
return newExchange;
} else {
Integer iterationsLeft = oldExchange.getProperty("PROPERTY", Integer.class);
oldExchange.setProperty("PROPERTY", iterationsLeft - 1);
return oldExchange;
}
}
})
.process(exchange -> {
Integer test = exchange.getProperty("PROPERTY", Integer.class);
System.out.println(test);
})
.end();
}
`
This code keeps printing 3 all the time and I wanted 3,2,1

Return values as array from collection

We have a collection of scrips :
{
"_id" : ObjectId("xxxxxxx"),
"scrip" : "3647"
}
{
"_id" : ObjectId("yyyyyy"),
"scrip" : "5647"
}
...
We are simply attempting to return the scrip numerals as an array of string using java driver 3.7
ArrayList<Document> scriplist = scrips.aggregate(Arrays.asList(
Aggregates.group(
Accumulators.push("scripids",
new Document("_id", "$id").
append("scripids", "$scripid"))
)
)).into(new ArrayList<>());
System.out.println(scriplist.toString());
Expected output is ['3647','5647'].
However,we get a 'Can't find a codec for class com.mongodb.client.model.BsonField.' exception.
How is this to be done?
The following query can get us the expected output:
db.scrips.distinct("scrip");
Output:
["3647","5647"]
Equivalent code in Java:
DistinctIterable<String> iterable = scrips.distinct("scrip", String.class);
List<String> scrips = new ArrayList<>();
Block<String> block = scrip -> scrips.add(scrip);
iterable.forEach(block);
The 'scrips' set would hold the distinct scrips.
Some other ways to do the same:
db.scrips.aggregate([
{
$group:{
"_id":"$scrip"
}
},
{
$group:{
"_id":null,
"scrips":{
$push:"$_id"
}
}
},
{
$project:{
"_id":0
}
}
])
Java code:
scrips.aggregate(
Arrays.asList(Aggregates.group("$scrip"), Aggregates.group(null, Accumulators.push("scrips", "$_id")),
Aggregates.project(Projections.exclude("_id"))));
db.scrips.aggregate([
{
$group:{
"_id":null,
"scrips":{
$addToSet:"$scrip"
}
}
},
{
$project:{
"_id":0
}
}
])
Java code:
scrips.aggregate(Arrays.asList(Aggregates.group(null, Accumulators.addToSet("scrips", "$_id")),
Aggregates.project(Projections.exclude("_id"))));

Protobuf and Java: put object into oneof

Suppose you have this protobuf model:
message ComplexKey {
string name = 1;
int32 domainId = 2;
}
message KeyMsg {
oneof KeyMsgOneOf {
string name = 1;
ComplexKey complexName= 2;
}
}
and an object obj, that you know is either a string or a ComplexKey.
Question
Whitout explicitly checking the obj class type, which is the most efficient way to build a new KeyMsg instance with the obj placed in the correct field using the protobuf Java API?
UPDATE: it would be great if protoc generates an helper method to do what I need.
UPDATE2: given the correct comment from Mark G. below and supposing that all fields differ in type, the best solution I've find so far is (simplified version):
List<FieldDescriptor> lfd = oneOfFieldDescriptor.getFields();
for (FieldDescriptor fieldDescriptor : lfd) {
if (fieldDescriptor.getDefaultValue().getClass() == oVal.getClass()) {
vmVal = ValueMsg.newBuilder().setField(fieldDescriptor, oVal).build();
break;
}
}
You can use switch-case:
public Object demo() {
KeyMsg keyMsg = KeyMsg.newBuilder().build();
final KeyMsg.KeyMsgOneOfCase oneOfCase = keyMsg.getKeyMsgOneOfCase();
switch (oneOfCase) {
case NAME: return keyMsg.getName();
case COMPLEX_NAME: return keyMsg.getComplexName();
case KEY_MSG_ONE_OF_NOT_SET: return null;
}
}
I doubt there is a better way than using instanceof:
KeyMsg.Builder builder = KeyMsg.newBuilder();
if (obj instanceof String) {
builder.setName((String) obj);
} else if (obj instanceof ComplexKey) {
builder.setComplexName((ComplexKey) obj);
} else {
throw new AssertionError("Not a String or ComplexKey");
}
KeyMsg msg = builder.build();

How to set multiple conditional opearator in java8

I am trying to convert the below code in java 8, but not sure where I am going wrong. I have 2 code snippets which I want to convert. This is the first one:
for (WebElement value :values) {
WebElement dateElement = SharedWebDriver.getInstance()
.findOptionalElement(By.className("text"), value);
WebElement groupElement =
SharedWebDriver.getInstance().findOptionalElement(By.id("label"),
value);
WebElement typeElement =
SharedWebDriver.getInstance().findOptionalElement(By.id("type"),
value);
if (dateElement != null) {
dateValue = dateElement.getText().trim();
}
if (groupElement != null) {
groupValue = groupElement.getText().trim();
}
if(typeElement!= null){
typeValue = typeElement.getText().trim();
}
}
And here I want to set value using java 8. I tried it with using the filter option, but it's not working.
for (WebElement header : headers) {
if (header != null) {
if (header.getText().equals("A")) {
entry.setDate(dateValue);
} else if (header.getText().equals("B")) {
entry.setGroup(groupValue);
} else if (header.getText().equals("C")) {
entry.setType(typeValue);
}
}
}
Can anyone help me?
The problem with those code snippets is that they modifiy variables defined outside of the loop (dateValue, groupValue and typeValue for the first one, and entry for the second one).
But lambda expressions are not really supposed to alter variables that are not defined in their scope event though you can achieve that throught methods.
For example, inside a lambda expression :
word = "hello" will not work whereas website.setTitle("title") will
I converted your code snippets in Java 8, I didn't take the time to test it but if I am if i am not mistaken, the first one will not work whereas the second one will, for the reason explained above.
values.stream()
.map(value -> new WebElement[] {
SharedWebDriver.getInstance().findOptionalElement(By.className("text"), value),
SharedWebDriver.getInstance().findOptionalElement(By.id("label"), value)),
SharedWebDriver.getInstance().findOptionalElement(By.id("type"), value) })
.forEach(webElements[] -> {
if (webElements[0] != null) {
dateValue = webElements[0].getText().trim();
}
if (webElements[1] != null) {
groupValue = webElements[1].getText().trim();
}
if(webElements[2] != null){
typeValue = webElements[2].getText().trim();
}
});
headers.stream()
.filter(Objects::nonNull)
.forEach(header -> {
if (header.getText().equals("A")) {
entry.setDate(dateValue);
} else if (header.getText().equals("B")) {
entry.setGroup(groupValue);
} else if (header.getText().equals("C")) {
entry.setType(typeValue);
}
});

Can I get data as JSON string when I am listening updates from RethinkDB?

Cursor changeCursor = r.table(Hardcoded.rethinkDBTableName()).changes().getField("new_val").without("id").run(conn);
for (Object change : changeCursor) {
System.out.println(change);
}
RESULT:
{
askPrice=1.29846,
symbol=EUR/USD,
bidTime=1455800529000,
askTime=1455800529000,
bidSize=1,
askSize=1,
bidPrice=1.2984
}
EXPECTED:
{
"askSize":1,
"askPrice":1.2978,
"askTime":1455729430000,
"bidTime":1455729430000,
"bidPrice":1.29778,
"symbol":"EUR/USD",
"bidSize":1
}
You can write r.table(Hardcoded.rethinkDBTableName()).changes().getField("new_val").without("id").map(val -> val.toJson()) and I think that will do what you want.

Categories

Resources