2008-09-28 12 views
2

Есть ли библиотеки, которые позволили бы мне использовать одну и ту же известную нотацию, которую мы используем в BeanUtils для извлечения POJO-параметров, но для простой замены замещающих элементов в строке?Простой способ использования «BeanUtils alike» заменить

Я знаю, что можно было бы свернуть самостоятельно, используя сами BeanUtils или другие библиотеки с похожими функциями, но я не хотел изобретать велосипед.

Я хотел бы взять строку следующим образом:

String s = "User ${user.name} just placed an order. Deliver is to be 
made to ${user.address.street}, ${user.address.number} - ${user.address.city}/
${user.address.state}"; 

И проходя один экземпляр класса User ниже:

public class User { 
    private String name; 
    private Address address; 
    // (...) 

    public String getName() { return name; } 
    public Address getAddress() { return address; } 
} 

public class Address { 
    private String street; 
    private int number; 
    private String city; 
    private String state; 

    public String getStreet() { return street; } 
    public int getNumber() { return number; } 
    // other getters... 
} 

Чтобы что-то вроде:

System.out.println(BeanUtilsReplacer.replaceString(s, user)); 

Would замените каждый заменитель на фактические значения.

Любые идеи?

ответ

2

Подвижной свой собственный, используя BeanUtils не будет принимать слишком много переосмысления колес (предполагая, что вы хотите, чтобы это было так же просто, как и было задано). Эта реализация использует контекст замены для замены, где ключ карты должен соответствовать первой части путей поиска переменных, заданных для замены.

import java.lang.reflect.InvocationTargetException; 
import java.util.Map; 
import java.util.regex.Matcher; 
import java.util.regex.Pattern; 

import org.apache.commons.beanutils.BeanUtils; 

public class BeanUtilsReplacer 
{ 
    private static Pattern lookupPattern = Pattern.compile("\\$\\{([^\\}]+)\\}"); 

    public static String replaceString(String input, Map<String, Object> context) 
     throws IllegalAccessException, InvocationTargetException, NoSuchMethodException 
    { 
     int position = 0; 
     StringBuffer result = new StringBuffer(); 

     Matcher m = lookupPattern.matcher(input); 
     while (m.find()) 
     { 
      result.append(input.substring(position, m.start())); 
      result.append(BeanUtils.getNestedProperty(context, m.group(1))); 
      position = m.end(); 
     } 

     if (position == 0) 
     { 
      return input; 
     } 
     else 
     { 
      result.append(input.substring(position)); 
      return result.toString(); 
     } 
    } 
} 

Учитывая переменные, представленные в вашем вопросе:

Map<String, Object> context = new HashMap<String, Object>(); 
context.put("user", user); 
System.out.println(BeanUtilsReplacer.replaceString(s, context)); 
1

См. Ответ на этот похожий вопрос о using Expression Language in a standalone context.

+0

insin, я не пошел по этому пути до тех пор, зная EL от реализации некоторых JSP, статья, которую вы указали, кажется быть точным *, что я искал! Благодаря! – kolrie 2008-09-28 03:09:22

+0

Я проголосовал за ваш вопрос, но я оставлю эту тему открытой, чтобы узнать, есть ли другие более простые решения. Если нет, я приму свой ответ. – kolrie 2008-09-28 03:11:04

1

Spring Framework должен иметь функцию, которая делает это (см. Пример Spring JDBC ниже). Если вы можете использовать groovy (просто добавьте файл groovy.jar), вы можете использовать функцию GroSty GString, чтобы сделать это довольно красиво.

Groovy пример

foxtype = 'quick' 
foxcolor = ['b', 'r', 'o', 'w', 'n'] 
println "The $foxtype ${foxcolor.join()} fox" 

Spring JDBC имеет функцию, которую я использую, чтобы поддерживать именованные и вложенные именованные переменные связывания из бобов, как это:

public int countOfActors(Actor exampleActor) { 

    // notice how the named parameters match the properties of the above 'Actor' class 
    String sql = "select count(0) from T_ACTOR where first_name = :firstName and last_name = :lastName"; 

    SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(exampleActor); 

    return this.namedParameterJdbcTemplate.queryForInt(sql, namedParameters); 
} 
1

Ваша строка пример является допустимым шаблон, по крайней мере, несколько шаблонных двигателей, как Velocity или Freemarker. Эти библиотеки предлагают способ слияния шаблона с контекстом, содержащим некоторые объекты (например, «пользователь» в вашем примере).

См http://velocity.apache.org/ или http://www.freemarker.org/

Некоторые примеры кода (с сайта Freemarker):

/* ------------------------------------------------------------------- */  
     /* You usually do it only once in the whole application life-cycle: */  

     /* Create and adjust the configuration */ 
     Configuration cfg = new Configuration(); 
     cfg.setDirectoryForTemplateLoading(
       new File("/where/you/store/templates")); 
     cfg.setObjectWrapper(new DefaultObjectWrapper()); 

     /* ------------------------------------------------------------------- */  
     /* You usually do these for many times in the application life-cycle: */  

     /* Get or create a template */ 
     Template temp = cfg.getTemplate("test.ftl"); 

     /* Create a data-model */ 
     Map root = new HashMap(); 
     root.put("user", "Big Joe"); 
     Map latest = new HashMap(); 
     root.put("latestProduct", latest); 
     latest.put("url", "products/greenmouse.html"); 
     latest.put("name", "green mouse"); 

     /* Merge data-model with template */ 
     Writer out = new OutputStreamWriter(System.out); 
     temp.process(root, out); 
     out.flush();