DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Data Engineering
  3. Data
  4. StringTemplate Part 3: Complex Data Types and Renderers

StringTemplate Part 3: Complex Data Types and Renderers

Collin Fagan user avatar by
Collin Fagan
·
Jun. 08, 10 · Interview
Like (0)
Save
Tweet
Share
24.90K Views

Join the DZone community and get the full member experience.

Join For Free

In Part 1 and Part 2 we dealt with simple data types who's string representation is well known. Complex data types may not have a string representation that meets the needs of a particular template.

// Example 1: Some objects don't have a useful toString()

Object objectParamater = new Object();

StringTemplate template = new StringTemplate("Hello $param$ !");

template.setAttribute("param", objectParamater);

System.out.println(template);

Output:

Hello java.lang.Object@18eb9e6 !

Your output will very but I think it's safe to say that in most cases this output is undesirable. Here is another example of a well intentioned toString() that just won't do for our purposes.

//Example 2: Even a well intentioned toString() methods may not be useful.

Planet mars = createMars();
template = new StringTemplate("Hello $param$ !");
template.setAttribute("param", mars);

System.out.println("Example 2:");
System.out.println(template);

Output:

Example 2:

Hello Planet [atmosphere=CO2 N2, diameter=0.532, inclinationToSunsEquator=5.65, mass=0.11,
moons=[Phobos, Deimos], name=Mars, orbitalEccentricity=0.093, orbitalPeriod=1.88,
orbitalRadius=1.52, rings=false, rotationPeriod=1.03] !

For object that follow the JavaBean specification (getters and setters) StringTemplate provides property access via the “.” notation. This allows you to access properties from within your template.

//Example 3: Dot notation for property access

template = new StringTemplate("Hello $planet.name$ !");
template.setAttribute("planet", createMars());

System.out.println("Example 3:");
System.out.println(template);

Output:

Example 3:

Hello Mars !

Now we are getting somewhere. The statement planet.name was translated by StringTemplate into a call to getName(). The object we pushed into the template has the name “Mars” so our output became “Hello Mars !”. If we take what we learned about collections (multi-valued attributes) in Part 2 and apply it to a collection of beans we can build more powerful templates.

/**
* Template to convert a collection of planets into a CSV file.
*/
toCSV(planets) ::= <<
Example 4:
Planet Listing
Name,Mass,Diameter,Orbital Period,Orbital Radius,Orbital Eccentricity,
Rotation Period,Inclination To Suns Equator,Rings,Atmosphere,

$planets:planetToCSVRow()$
>>

/**
* Creates a single row of comma separated values
*/
planetToCSVRow(planet) ::= <<

$planet.name$,$planet.mass$,$planet.diameter$,$planet.orbitalPeriod$,$planet.orbitalRadius$,
$planet.orbitalEccentricity$,$planet.rotationPeriod$,$planet.inclinationToSunsEquator$,$planet.rings$,
$planet.atmosphere$

>>

This generates CSV data with a header and named columns. I think it's important to note that we pushed data into this template that same way we always have .

template.setAttribute("planets",createPlanets());

We have shifted complexity from the Java code to the template where we can deal with it more effectively. Here is the output from example 4.

Example 4:
Planet Listing

Name,Mass,Diameter,Orbital Period,Orbital Radius,Orbital Eccentricity,Rotation Period,Inclination To Suns Equator,Rings,Atmosphere,
Mercury,0.06,0.382,0.24,0.39,0.206,58.64,3.38,false,Minimal
Venus,0.82,0.949,0.62,0.72,0.0070,-243.02,3.86,false,CO2 N2
Jupiter,317.8,11.209,11.86,5.2,0.048,0.41,6.09,true,H2 HE
Saturn,95.2,9.449,29.46,9.54,0.054,0.43,5.51,true,H2 HE
Neptune,17.2,3.883,164.8,30.06,0.0090,0.67,6.43,true,H2 HE
Earth,1.0,1.0,1.0,1.0,0.017,1.0,7.25,false,N2 O2
Mars,0.11,0.532,1.88,1.52,0.093,1.03,5.65,false,CO2 N2

Here we have nice CSV output. When a column is added or removed all we need to do it make the appropriate change in the template. The source code does not need to change. Static header or footer information can be added with no impact on Java code.

All planetary data was taken from: http://en.wikipedia.org/wiki/Planet

Renderers:

In all our previous examples we could, at some point, obtain an adequate string representation of our data without fiddling around too much. This will not always be the case. As an example of how to deal with this I will use a data type notorious for needing special attention, java.util.Date. Lets start simply with the following Java code.

// Example 5: Unformatted Date
template = new StringTemplate("The current date is: $now$ !");
template.setAttribute("now", new Date());

System.out.println("Example 5:");
System.out.println(template);<span style="text-decoration: none;"> </span>

Output:

Example 5:
The current time is: Fri Jun 04 08:01:48 CDT 2010 !

 

While this does accurately report the current time it may not be in a form familiar to your users. In this case there is no property that we can use as our preferred display value. StringTemplate provides a system for intercepting an object before it gets turned into a string. This is called a “Renderer”.

Here is the skeleton of a simple Renderer. ( AttributeRenderer has a second method but lets ignore that for now.)

public class DateRenderer implements AttributeRenderer {

@Override
public String toString(Object attribute) {
return null;
}
}

The original attribute is passed as a parameter to the toString() method. The return value from the toString() method becomes the new value placed in the template. For Dates we can leverage the SimpleDateFormat (http://java.sun.com/javase/6/docs/api/java/text/SimpleDateFormat.html) class to do the actual formatting.

public class StaticDateRenderer implements AttributeRenderer{

private SimpleDateFormat format;

public StaticDateRenderer(String pattern){
format = new SimpleDateFormat(pattern);
}

@Override
public String toString(Object attribute) {
return format.format((Date) attribute);
}
...
}

As you can see we are just delegating to an instance of SimpleDateFormat. The cast to a Date is always safe because we register a rendered by the class literal.

template.registerRenderer(Date.class,new StaticDateRenderer("h:m:ss a"));

When we add the above line to our previous example we see that the date now appears in a more familiar from.

Example 5: Using a Date Renderer

The current time is: 7:51:08 AM !

Renders are specified per class. This means that if we had two dates in the above example they would both use the “h:m:ss a” format. This would be undesirable if for instance we had two column in a table, one was a date and one was a time. Luckily AttributeRenderer provides a second method to help deal with this.

public String toString(Object attribute, String format)

This method takes the attribute to be rendered and a format parameter. This format parameter is passed from the template to the render.

$now; format="SHORT"$

In this case the toString method is passed the value 'SHORT'. It's up to the render to decide what to do with any particular parameter. DynamicDateRenderer is an example of a render that utilizes the format parameter to effect the formatting of a particular date. It supports the formatting styles from DateFormat and the SimpleDateFormat pattern syntax.

Example 6: Formatting Dates

DateFromat Styles:

DEFAULT $now$
SHORT $now; format="SHORT"$
MEDIUM $now; format="MEDIUM"$
LONG $now; format="LONG"$
FULL $now; format="FULL"$

Using SimpleDateFormat Patterns:

yyyy.MM.dd G 'at' HH:mm:ss z $now; format="yyyy.MM.dd G 'at' HH:mm:ss z"$
EEE, MMM d, ''yy $now; format="EEE, MMM d, ''yy"$
h:mm a $now; format="h:mm a"$
hh 'o''clock' a, zzzz $now; format="hh 'o''clock' a, zzzz"$
K:mm a, z $now; format="K:mm a, z"$
yyyyy.MMMMM.dd GGG hh:mm aaa $now; format="yyyyy.MMMMM.dd GGG hh:mm aaa"$
EEE, d MMM yyyy HH:mm:ss Z $now; format="EEE, d MMM yyyy HH:mm:ss Z"$
yyMMddHHmmssZ $now; format="yyMMddHHmmssZ"$
yyyy-MM-dd'T'HH:mm:ss.SSSZ $now; format="yyyy-MM-dd'T'HH:mm:ss.SSSZ"$
dd.MM.yy $now; format="dd.MM.yy"$
h:mm a $now; format="h:mm a"$
H:mm $now; format="H:mm"$
H:mm:ss:SSS $now; format="H:mm:ss:SSS"$

(The syntax hilighter is having troubles with the spacing in this block. Please click "view source" to see the actual template.)

The template uses the same variable in every line, only the formatting parameter changes. On one side I have put the description of the date format. On the other side I have applied the format to the date value. Below is the final output from the above template.

Example 6: Formatting Dates

DateFromat Styles:

DEFAULT Jun 7, 2010
SHORT 6/7/10
MEDIUM Jun 7, 2010
LONG June 7, 2010
FULL Monday, June 7, 2010

Using SimpleDateFormat Patterns:

yyyy.MM.dd G 'at' HH:mm:ss z 2010.06.07 AD at 21:00:18 CDT
EEE, MMM d, ''yy Mon, Jun 7, '10
h:mm a 9:00 PM
hh 'o''clock' a, zzzz 09 o'clock PM, Central Daylight Time
K:mm a, z 9:00 PM, CDT
yyyyy.MMMMM.dd GGG hh:mm aaa 02010.June.07 AD 09:00 PM
EEE, d MMM yyyy HH:mm:ss Z Mon, 7 Jun 2010 21:00:18 -0500
yyMMddHHmmssZ 100607210018-0500
yyyy-MM-dd'T'HH:mm:ss.SSSZ 2010-06-07T21:00:18.668-0500
dd.MM.yy 07.06.10
h:mm a 9:00 PM
H:mm 21:00
H:mm:ss:SSS 21:00:18:668

(The syntax hilighter is having troubles with the spacing in this block. Please click "view source" to see the actual output.)

Renders are a powerful system for converting data into template friendly forms. As a rule of thumb when you are combining data you should use a template. When the data itself needs to take on a different form it's time to consider a renderer.

This concludes part 3. I hope you give StringTemplate a try. As always, if you want more information please see the official StringTemplate documentation.

Example source code (eclipse project)

From http://weblogs.java.net/blog/aberrant/archive/2010/06/07/stringtemplate-part-3-complex-data-types-and-renderers

Data (computing) Data Types Template

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Keep Your Application Secrets Secret
  • Application Architecture Design Principles
  • Kubernetes-Native Development With Quarkus and Eclipse JKube
  • A First Look at Neon

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: