Jason R. Coombs
Jason R. Coombs

Reputation: 42694

Formatting a string in Java using class attributes

I have a class with an attribute and getter method:

public Class MyClass
{
  private String myValue = "foo";

  public String getMyValue();
}

I would like to be able to use the value of foo in a formatted string as such:

String someString = "Your value is {myValue}."
String result = Formatter.format(someString, new MyClass());
// result is now "Your value is foo."

That is, I would like to have some function like .format above which takes a format string specifying properties on some object, and an instance with those properties, and formats the string accordingly.

Is it possible to do accomplish this feat in Java?

Upvotes: 5

Views: 3751

Answers (4)

Stephen Denne
Stephen Denne

Reputation: 37047

(My other answer's probably only useful if you're already using struts.)

Similar to sdb's answer, there is apache JEXL.

The UnifiedJEXL class provides template-like functionality, so you can write (as shown in javadocs):

JexlEngine jexl = new JexlEngine();
UnifiedJEXL ujexl = new UnifiedJEXL(jexl);
UnifiedJEXL.Expression expr = ujexl.parse("Hello ${user}");
String hello = expr.evaluate(context, expr).toString();

(The expr not only looks strange being passed as a parameter to a method on itself, but is indeed not needed as a parameter)

The context setup is shown earlier in the same page:

// Create a context and add data
JexlContext jc = new MapContext();
jc.set("foo", new Foo() );

You'll also need either commons-logging, or you can configure JEXL to use your own logger.


So to get close to what you asked, you can create:

public class Formatter {
    public static String format(String format, Object ... inputs) {
        JexlContext context = new MapContext();
        for (int i=0;i<inputs.length;i++) {
            context.set("_" + (i+1), inputs[i] );
        }
        JexlEngine jexl = new JexlEngine();
        UnifiedJEXL ujexl = new UnifiedJEXL(jexl);
        UnifiedJEXL.Expression expr = ujexl.parse(format);
        return expr.evaluate(context).toString();
    }
}

and call it with

String someString = "Your value is ${_1.myValue}.";
String result = Formatter.format(someString, new MyClass());

At which point, result is "Your value is foo."

Upvotes: 2

Stefan De Boey
Stefan De Boey

Reputation: 2394

you could use JUEL for this. it's an implementation of the Java Expression Language. the code is rather compact and looks like this:

ExpressionFactory factory = new ExpressionFactoryImpl();

// create a context and add a Person object to the context, this variable will be used
// in the property replacement
// objects of type Person have two fields: firstName and lastName

SimpleContext context = new SimpleContext();
Person person = new Person("John", "Doe");
context.setVariable("person", factory.createValueExpression(person, Person.class));

// create the expression

String expr = "My name is ${person.firstName} ${person.lastName}";
ValueExpression e = factory.createValueExpression(context, expr, String.class);

// evaluate the expression
System.out.println(e.getValue(context));

which prints 'My name is John Doe'

note that it's also possible to use an expression like this: '${firstName}' instead of '${person.firstName}', but then you will have to write and provide a custom resolver (javax.el.ELResolver) for the variable and property resolution

Upvotes: 3

Stephen Denne
Stephen Denne

Reputation: 37047

You could create one with struts2/xwork/OGNL, similar to the below (copied from an email from Vlad)

public static String translateOgnl(String message, Map<Object, Object> args) {
    OgnlValueStack stack = new OgnlValueStack();
    stack.push(args);
    return TextParseUtil.translateVariables(message, stack);
}

The javadocs for TextParseUtil.translateVariables() say

Converts all instances of ${...} in expression to the value returned by a call to ValueStack.findValue(java.lang.String). If an item cannot be found on the stack (null is returned), then the entire variable ${...} is not displayed, just as if the item was on the stack but returned an empty string.

Upvotes: 0

BalusC
BalusC

Reputation: 1109522

It's in theory possible with a stackbased parser to determine the valueholders in the string, in combination with reflection (or better, a Javabean inspection API, such as Commons BeanUtils) to get the bean property values.

Unfortunately no ready-made nor 3rd party API comes to mind, if you were looking for that. It's an interesting question however.

Upvotes: 0

Related Questions