Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java comparison #161

Merged
merged 1 commit into from
Apr 7, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/language/java_comparison/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.class
92 changes: 92 additions & 0 deletions doc/language/java_comparison/BaseTemplate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
Copyright 2016 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class BaseTemplate extends JsonnetObject {
public Set<String> nonHiddenFields() {
Set<String> r = super.nonHiddenFields();
r.addAll(Arrays.asList("apiVersion", "kind", "spec"));
return r;
}

// Mandatory param
public Object accessToken() {
throw new RuntimeException("accessToken must be defined");
}

// Optional params
public Object image() { return "gcr.io/cooltool-1009/pipeline_image:latest"; }
public Object[] extraEnv() { return new Object[]{}; }

public Object apiVersion() { return "v1"; }
public Object kind() { return "ReplicationController"; }

public class BaseTemplateSpec extends JsonnetObject {
public Set<String> nonHiddenFields() {
Set<String> r = super.nonHiddenFields();
r.addAll(Arrays.asList("replicas", "spec"));
return r;
}

public Object replicas() { return 1.0; }

public class BaseTemplateSpecSpec extends JsonnetObject {
public Set<String> nonHiddenFields() {
Set<String> r = super.nonHiddenFields();
r.addAll(Arrays.asList("containers"));
return r;
}

public class Container0 extends JsonnetObject {
public Set<String> nonHiddenFields() {
Set<String> r = super.nonHiddenFields();
r.addAll(Arrays.asList("env", "image", "name"));
return r;
}

class Env0 extends JsonnetObject {
public Set<String> nonHiddenFields() {
Set<String> r = super.nonHiddenFields();
r.addAll(Arrays.asList("name", "value"));
return r;
}
public Object name() { return "ACCESSTOKEN"; }
public Object value() { return BaseTemplate.this.accessToken(); }
}

public Object[] env() {
// Concatenating arrays (first + second) is hard in Java.
Object[] first = new Object[]{ new Env0() };
Object[] second = BaseTemplate.this.extraEnv();
Object[] result = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, result, first.length, second.length);
return result;
}
public Object image() { return BaseTemplate.this.image(); }
public Object name() { return "twitter-to-redis"; }
}

public Object containers() { return new Object[] { new Container0() }; }
}
public Object spec() { return new BaseTemplateSpecSpec(); }

}
public Object spec() { return new BaseTemplateSpec(); }
}

22 changes: 22 additions & 0 deletions doc/language/java_comparison/JsonnetObject.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
Copyright 2016 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import java.util.HashSet;
import java.util.Set;

public class JsonnetObject {
public Set<String> nonHiddenFields() { return new HashSet<String>(){}; }
}
81 changes: 81 additions & 0 deletions doc/language/java_comparison/JsonnetValue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
Copyright 2016 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.util.HashSet;
import java.util.Set;

public class JsonnetValue {
public static String manifest(Object value) {
StringBuffer buf = new StringBuffer();
if (value == null) {
// FIXME: does not escape the string
buf.append("null");

} else if (value instanceof String) {
// FIXME: does not escape the string
buf.append("\"" + value + "\"");

} else if (value instanceof Double) {
buf.append(value.toString());

} else if (value instanceof Boolean) {
buf.append(value.toString());

} else if (value instanceof Object[]) {
Object[] arr = (Object[]) value;
buf.append("[");
String prefix = " ";
for (Object element : arr) {
buf.append(prefix);
prefix = ", ";
buf.append(manifest(element));
}
buf.append(" ]");

} else if (value instanceof JsonnetObject) {
JsonnetObject obj = (JsonnetObject) value;
buf.append("{");
String prefix = " ";
for (String field : obj.nonHiddenFields()) {
buf.append(prefix);
prefix = ", ";
buf.append("\"" + field + "\": ");
try {
Method method = obj.getClass().getMethod(field);
Object fieldValue = method.invoke(obj);
buf.append(manifest(fieldValue));
} catch (IllegalArgumentException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
} catch (InvocationTargetException e) {
System.out.println(e);
} catch (SecurityException e) {
System.out.println(e);
} catch (NoSuchMethodException e) {
System.out.println(e);
}
}
buf.append(" }");
} else {
throw new RuntimeException("Got weird type: " + value.getClass());
}
return buf.toString();
}
}

58 changes: 58 additions & 0 deletions doc/language/java_comparison/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
Jsonnet to Java
---------------

This little code example shows how a Jsonnet config using object-oriented features can be
transliterated (in a structure-preserving manner) to use the object-oriented features of Java. Not
all Jsonnet programs can be converted to Java because Jsonnet has mixins and virtual inner classes.
The semantics are also different, as Jsonnet is lazy and Java is eager. Likewise, Java programs
cannot all be converted to Jsonnet because they have mutable state and I/O.

However said all this, there is a significant overlap between the two languages. This example fits
within that overlap.


Execute Jsonnet code
--------------------

```
jsonnet sub-template.jsonnet
```


Execute Java code
-----------------

We pipe into jsonnet - to pretty-print the output JSON.

```
javac *.java && java Test | jsonnet -
```


Structure of Java code
----------------------

The translation is as as follows:

* Everything is typed as Object, as Jsonnet is dynamically typed.
* Jsonnet arrays are Object[], and primitives are Boolean / Double / String.
* Jsonnet objects because singleton instances of Java classes that extend JsonnetObject.
* Jsonnet fields become Java methods with no parameters (fields are virtual in Jsonnet).
* Jsonnet hidden field status is represented with a method nonHiddenFields which returns a set of
field names. Other fields are considered hidden.
* There are 2 liberties taken -- output strings are not escaped properly, and the JSON is printed on
a single line instead of pretty-printed with indenting.

The Java code has a number of auxiliary framework functions to provide Jsonnet functionality that is
implicit in the Jsonnet language.

* The Test class chooses an object and manifests it to stdout.
* The JsonnetValue class implements manifestation, as a visitor over possible JSON values that
builds JSON strings. For objects, it iterates over the non-hidden fields and manifests each value
by reflectively calling that function.


Reference JSON
--------------

For reference, the JSON that should be output is given in sub-template.json
31 changes: 31 additions & 0 deletions doc/language/java_comparison/SubTemplate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
Copyright 2016 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

public class SubTemplate extends BaseTemplate {
// Supply my access token and pinned version.
public String accessToken() {
return "xxxxx";
}
public String image() {
return "gcr.io/cooltool-1009/pipeline_image@sha256:....";
}
public class SubTemplateSpec extends BaseTemplate.BaseTemplateSpec {
public Object replicas() { return 2.0; }
}
public Object spec() {
return new SubTemplateSpec();
}
}
21 changes: 21 additions & 0 deletions doc/language/java_comparison/Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
Copyright 2016 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

public class Test {
public static void main(String[] args) {
System.out.println(JsonnetValue.manifest(new SubTemplate()));
}
}
44 changes: 44 additions & 0 deletions doc/language/java_comparison/base-template.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
Copyright 2016 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

{
// Mandatory param
accessToken:: error "accessToken must be defined",

// Optional params
image:: "gcr.io/cooltool-1009/pipeline_image:latest",
extraEnv:: [],

apiVersion: "v1",
kind: "ReplicationController",
spec: {
replicas: 1,
spec: {
containers: [
{
env: [
{
name: "ACCESSTOKEN",
value: $.accessToken,
},
] + $.extraEnv,
image: $.image,
name: "twitter-to-redis",
},
],
},
},
}
21 changes: 21 additions & 0 deletions doc/language/java_comparison/sub-template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"apiVersion": "v1",
"kind": "ReplicationController",
"spec": {
"replicas": 2,
"spec": {
"containers": [
{
"env": [
{
"name": "ACCESSTOKEN",
"value": "xxxxx"
}
],
"image": "gcr.io/cooltool-1009/pipeline_image@sha256:....",
"name": "twitter-to-redis"
}
]
}
}
}
Loading