Pergunta

Há qualquer biblioteca que permita-me usar a mesma notação conhecido como usamos em BeanUtils para extrair parâmetros POJO, mas para substituir facilmente espaços reservados em uma string?

Eu sei que seria possível fazer a minha própria, usando BeanUtils si mesmo ou outras bibliotecas com características semelhantes, mas eu não queria reinventar a roda.

Eu gostaria de ter uma seqüência como segue:

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}";

E passando uma instância da classe de usuário abaixo:

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...
}

Para algo como:

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

iria ficar cada espaço reservado substituído por valores reais.

Todas as idéias?

Foi útil?

Solução

Rolando seus próprios usando BeanUtils não tomaria muito reinvenção da roda (supondo que você quer que ele seja tão básico como pediu). Esta implementação tem um mapa para o contexto de substituição, onde a chave mapa deve corresponder à primeira parte dos caminhos de pesquisa variável dada para a substituição.

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();
        }
    }
}

Dadas as variáveis ??fornecidas na sua pergunta:

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

Outras dicas

Veja a resposta a esta pergunta semelhante sobre usando Expression Language em um contexto autônomo .

Spring Framework deve ter uma característica que faz isso (veja o exemplo da Primavera JDBC abaixo). Se você pode usar Groovy (basta adicionar o arquivo groovy.jar), você pode usar o recurso gstring do Groovy para fazer isso muito bem.

exemplo Groovy

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

Spring JDBC tem uma característica que eu uso para apoiar o nome e aninhados variáveis ??de ligação com o nome de feijão como esta:

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);
}

Seu exemplo string é um modelo válido em pelo menos alguns motores de templates, como velocidade ou Freemarker. Estas bibliotecas oferecem uma maneira de mesclar um modelo com um contexto contendo alguns objetos (como 'usuário' no seu exemplo).

Consulte http://velocity.apache.org/ ou http://www.freemarker.org/

Alguns códigos de exemplo (a partir do site do 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();
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top