How to generate a Java function that can convert `List<List<Integer>>` to a JSON string?

37 views
Skip to first unread message

Frank Dai

unread,
Jul 15, 2015, 5:35:19 PM7/15/15
to stringtempla...@googlegroups.com

I want to generate a toJson() function that can convert a java.util.List to a JSON string.


For example, here is my java.stg group file:

list_to_json(type, name) ::= <<
String toJson(<type> <name>) {
    final StringBuilder result = new StringBuilder("[");
    for (final int i : <name>) {
        result.append(i);
        result.append(',');
    }
    if (!<name>.isEmpty()) result.setLength(result.length() - 1);
    result.append(']');
    return result.toString();
}
>>


If I assign a value List<Integer> to type,

final STGroup group = new STGroupFile("java.stg");
final ST st = STGroups.javaGroup.getInstanceOf("list_to_json");
st.add("type", "List<Integer>");
st.add("name", "list");
System.out.println(st.render());


It will output a Java function:

String toJson(List<Integer> list) {
    final StringBuilder result = new StringBuilder("[");
    for (final int i : list) {
        result.append(i);
        result.append(',');
    }
    if (!list.isEmpty()) result.setLength(result.length() - 1);
    result.append(']');
    return result.toString();
}


which can successfully convert a List<Integer> to a JSON string:

System.out.println(toJson(Arrays.asList(1,2,3)));


But what if I want to set type to List<List<Integer>, or even List<List<List<Integer>>>?


Is StringTemplate capable of recursively generating code? How to deal with List<List<Integer>> ?

Terence Parr

unread,
Jul 15, 2015, 5:48:40 PM7/15/15
to stringtempla...@googlegroups.com
Hi. Recursion is no problem. Have a template refer to itself, passing in a smaller bit of the data each time :)
Ter
--
You received this message because you are subscribed to the Google Groups "stringtemplate-discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to stringtemplate-dis...@googlegroups.com.
To post to this group, send email to stringtempla...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/stringtemplate-discussion/149a69d9-dd89-45ba-9136-5345bb2d2938%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

geoff...@empowerops.com

unread,
Jun 21, 2016, 5:45:45 PM6/21/16
to stringtemplate-discussion
On Wednesday, July 15, 2015 at 2:35:19 PM UTC-7, Frank Dai wrote:
> I want to generate a toJson() function that can convert a java.util.List to a JSON string.
>
>
> For example, here is my java.stg group file:list_to_json(type, name) ::= <<
> String toJson(<type> <name>) {
> final StringBuilder result = new StringBuilder("[");
> for (final int i : <name>) {
> result.append(i);
> result.append(',');
> }
> if (!<name>.isEmpty()) result.setLength(result.length() - 1);
> result.append(']');
> return result.toString();
> }
> >>
>
>
>
> If I assign a value List<Integer> to type,final STGroup group = new STGroupFile("java.stg");

> final ST st = STGroups.javaGroup.getInstanceOf("list_to_json");
> st.add("type", "List<Integer>");
> st.add("name", "list");
> System.out.println(st.render());
>
>
>
> It will output a Java function:String toJson(List<Integer> list) {
> final StringBuilder result = new StringBuilder("[");
> for (final int i : list) {
> result.append(i);
> result.append(',');
> }
> if (!list.isEmpty()) result.setLength(result.length() - 1);
> result.append(']');
> return result.toString();
> }
>
>
>
> which can successfully convert a List<Integer> to a JSON string:System.out.println(toJson(Arrays.asList(1,2,3)));
>
>
>
> But what if I want to set type to List<List<Integer>, or even List<List<List<Integer>>>?
>
>
> Is StringTemplate capable of recursively generating code? How to deal with List<List<Integer>> ?


This is a really fun question, can I ask the obvious though: Why are you using String Template to generate source code that converts runtime objects into JSON strings, when you could just cut-to-the-chase and use StringTemplate to generate those JSON strings for you? Or, why not simply use GSON?

Anyways, to parrt's response, I believe the format would be something like

file:list_to_json(type, name) ::= <<
String toJson(<type.wildCard> <name>) {


final StringBuilder result = new StringBuilder("[");

for (final Object nextElement : <name>) {
<if(type.innerClass)>
result.append(toJson(<type.innerClass>, (<type.wildCard>)nextElement))
<else>
result.append(nextElement);
<endif>


result.append(',');
}
if (!<name>.isEmpty()) result.setLength(result.length() - 1);
result.append(']');
return result.toString();
}
>>

needless to say this has you implementing and object with `wildCard` and `innerClass` properties. Annoyingly reflection's not going to help you too much here thanks to type erasure (in other words, you cant simply replace `wildCard` with `simpleName` and `innerClass` with `getTemplateWhatever`, and then use a java.lang.reflect.Class object mapped to `type`, because at runtime it wont know what its generic type parameters are). You might have better luck with guava's TypeLiteral hack, or you could make your own object that simply uses strings and substring methods.

I'd be interested in what solution you chose to implement!

cheers,

-Geoff

Reply all
Reply to author
Forward
0 new messages