Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how do I iterate though a java list in stringtemplate?

I want to iterate through a hibernate query results inside stringtemplate. I've been looking for examples but I can't find anything.

can you please help? thanks

like image 345
mrjayviper Avatar asked Aug 26 '13 05:08

mrjayviper


1 Answers

The syntax looks like

<items :{ item | <item> }>

Putting it together in Java:

List<String> teams = Arrays.asList("Cats", "Birds", "Turtles");
ST s = new ST( "<teams :{team | <team> }>");
s.add("teams", teams);
System.out.println(s.render());

In this example, I iterate over the List and print each team that is in the teams list. The result that would be printed is:

Cats Birds Turtles 

We can explore the syntax that makes this happen. Before we do, remember, that the default delimiters in StringTemplate are less than < and greater than >. Since we didn't specify a different delimiter < > will be what we use in our example.See more about delimiters

:{ }

This set of symbols, the colon : and the open and closed brace {} can be read as "for each". In the example template, the code reads, for each team in teams print team. The left side of the vertical pipe | indicates the variable that will be created for each iteration. It will hold the current team from the list of teams. The print is composed of the <team> on the right side of the vertical pipe | and the left side of the closing brace }. Anything that is on the right side of the vertical pipe | and before the closing base } will be evaluated to be printed.

:{ current value | everything in here will be printed }

In order to build on the concept, let's use a more complex data structure.

public class Player {
    private String name;
    private int age;

    public Person(String name, int age) { 
        this.name = name; 
        this.age = age; 
    }
    public int getAge() { return age; }
    public String getName() { return name; }
}

Now we can create a few players for our team:

Player[] players = new Player[] {
    new Player("Bill", 29),
    new Player("Steve", 30),
    new Player("Toby", 15)
};

String playerTemplate = "<players:{ player |<player.name> is <player.age> <\\n>}>"
ST s = new ST( playerTemplate  );
s.add("players", Arrays.asList(players));
System.out.println(s.render());

Giving a result of

Bill is 29
Steve is 30
Toby is 15

Couple of things to note. We didn't access the properties age and name directly. ST called the methods getAge and getName. ST doesn't look to the properties. Instead, it looks to find the access methods.

What if we just wanted to iterate over a list that contained another list. We can do that as well. First, let's build up our data structure and fill it with a couple of lists.

List<List<String>> listOfLists = asList(
    asList("One", "Two", "Three"), 
    asList("Four", "Five"), 
    asList("Six", "Seven", "Eight", "Nine")
);

The template will look like the following.

<list :{ items |<items :{ item |<item> }><\n>}>

Our template, in this case, will just be a combination. The outer shell will iterate over the list we will hand in.

 <list :{ items |  what we will print   }>

Then for each item, we will print out the items in its list.

<items :{ item |<item> }>

Once we put it all together

String template = "<list :{ items |<items :{ item |<item> }><\\n>}>";
ST st = new ST( template);
st.add("list", listOfLists);
System.out.println(st.render());

We get a result that looks like the following.

One Two Three 
Four Five 
Six Seven Eight Nine 

Building on this concept a little more we can create a second data structure that contains a list of players. This will demonstrate how to iterate within iteration.

The first thing we will need is a data structure that contains a list. For this we can create a Team for our players to be a part.

public class Team {
    private List<Player> players;
    private String name;

    public Team (String name, List<Player> players) {
        this.players = players;
        this.name = name;
    }

    public List<Player> getPlayers() {
        return players;
    }

    public String getName() {
        return name;
    }
}

Notice that our team contains players. This composition will allow us to build up two iterations.

Now that we have our data structure lets set everything together to make a couple of teams with some players.

List<Team> teams = asList(
        new Team("Billings", asList(
                new Player("Bill", 29),
                new Player("Steve", 30),
                new Player("Toby", 15)
        )),
        new Team("Laurel", asList(
                new Player("Chad", 32),
                new Player("Chuck", 29),
                new Player("Will", 24),
                new Player("Ben", 26)
        ))
);

Now lets create a template and fill in a few details:

String simpleTeamTemplate = "<teams:{ team |<team.name> has <length(team.players)> players<\\n>}>";

ST template = new ST( simpleTeamTemplate );
template.add("teams", teams);

System.out.println(template.render());

That will print out

Billings has 3 players
Laurel has 4 players

Our simple template is just about the same as our first template from above. The only real difference is that we are using a built-in method provided by ST length(). See more on functions here

Let's increase the complexity of the templates a little to add in our second iteration.

First, we will create our playersTemplate. This is almost identical to our playerTemplate template from above. The only difference is that we have our players coming from a team: team.players.

String playersTemplate = "<team.players :{ player |<player.name> is <player.age><\\n>}>";

Now we will construct a second template that contains the first. In this template we can iterate over teams and for each team we will print out the name, number of players length(team.players), and everything in the playersTemplate.

String teamTemplate = "<teams:{ team |<team.name> has <length(team.players)> players<\\n>"+playersTemplate+"}>"; 

Now let's put that all together.

ST teamsTemplate = new ST( simpleTeamTemplate);
teamsTemplate.add("teams", teams);

System.out.println(teamsTemplate.render());

That will print for us the following.

Billings has 3 players
Bill is 29
Steve is 30
Toby is 15
Laurel has 4 players
Chad is 32
Chuck is 29
Will is 24
Ben is 26

Now, you aren't really going to want to combine your templates in this way. Appending strings together to compose templates is rather silly. StringTemplate offers tools to make this combination of partial templates very easy. If you are curious about combining templates you can find out more here

like image 195
Chuck Lowery Avatar answered Sep 27 '22 18:09

Chuck Lowery