views:

158

answers:

2

Here is the basic code i'm trying to make work:

Field fields[] = SalesLetter.class.getDeclaredFields();
String fieldName;

for (int j = 0, m = fields.length; j < m; j++) {
       fieldName = fields[j].getName(); //example fieldname [[headline]]
       templateHTML = templateHTML.replace(fieldName, Letter.fieldName());
}

I believe I'm going about it wrong by trying to getDeclaredFields (which isn't even syntactically correct). When I finished my title, it came up with a few other stackoverflow questions which I read before writing this. They were:

http://stackoverflow.com/questions/20267/best-way-to-replace-tokens-in-a-large-text-template http://stackoverflow.com/questions/1619739/replacing-tokens-in-a-string-from-an-array

It gave me the idea of reading all legal [[tokens]] from a text file, putting them into a hash (err I mean map, this is java :D), then creating an object reference with the same name as that token.

I can't figure out how I would do such a thing in java specifically, or if that would work. Please assist.

Thanks in advance,

Cody Goodman

Note: I'm trying to make everything as flexible as possible, so maybe in the future I could add things such as "[[tokenname]]:this is token name, you need to really think about what the customer wants to come up with a good token name" in a text file, then those fields are generated on my form, and everything works :)

A: 

What about using a template engine like Freemarker, Velocity or StringTemplate:

  • replace [[ by ${ and ]] by }
  • create a model from a properties file containing the replacements
  • process templateHTML

Here an example with Freemarker (without Exception handling)

Configuration config = new Configuration();
StringTemplateLoader loader = new StringTemplateLoader();
config.setTeplateLoader(loader);

Map model = Properites.load(new FileInputStream("tokens.properties"));
loader.putTemplate("html.ftl", templateHTML);
Template template = config.getTemplate("html.ftl");

Writer out = new StringWriter();
template.process(root, out);
String result = out.toString();

StringTemplate may be more simple (replace [[ and ]] by $), but I am not fimilar with it:

Map model = Properites.load(new FileInputStream("tokens.properties"));
StringTemplate template = new StringTemplate(templateHTML);
template.setAttributes(model);
String result = template.toString();

The tokens.properties file looks like:

tokenname:this is token name
Arne Burmeister
This looks interesting, and really flexible. I'll see if I can't put code together with this to. Love the simplicity here though. Thanks.
Codygman
+1  A: 

In order to read values from non-static fields of a type, you'll need a reference to an instance of the type:

public class ReflectFields {
  static class Letter {
    public int baz = 100;
  }

  static class SalesLetter extends Letter {
    public String foo = "bar";
  }

  public static void main(String[] args) throws Exception {
    // TODO: better exception handling, etc.
    SalesLetter instance = new SalesLetter();
    for (Field field : instance.getClass().getFields()) {
      System.out.format("%s = %s%n", field.getName(), field.get(instance));
    }
  }
}

You'll also have to watch for private fields, etc. In general, this approach should be avoided as it breaks encapsulation by looking at class internals.

Consider using the JavaBean API.

public class BeanHelper {
  private final Object bean;
  private final Map<String, Method> getters = new TreeMap<String, Method>();

  public BeanHelper(Object bean) {
    this.bean = bean;
    for (PropertyDescriptor pd : Introspector.getBeanInfo(bean.getClass(),
          Object.class).getPropertyDescriptors()) {
      getters.put(pd.getName(), pd.getReadMethod());
    }
  }

  public Set<String> getProperties() { return getters.keySet(); }

  public Object get(String propertyName) {
    return getters.get(propertyName).invoke(bean);
  }

  public static void main(String[] args) {
    BeanHelper helper = new BeanHelper(new MyBean());
    for (String prop : helper.getProperties()) {
      System.out.format("%s = %s%n", prop, helper.get(prop));
    }
  }

  public static class MyBean {
    private final String foo = "bar";
    private final boolean baz = true;
    public String getFoo() { return foo; }
    public boolean isBaz() { return baz; }
  }
}

Exception handling has been omitted for brevity, so you'll need to add some try/catch blocks (I suggest wrapping the caught exceptions in IllegalStateExceptions).

McDowell
Just beginning java, so I think i'm going to have to read some javadocs before I fully appreciate this answer. Thanks for the help! I'll see if I can't throw something together with this code.
Codygman