Pregunta

¿Hay alguna biblioteca que me permita usar la misma notación conocida que usamos en BeanUtils para extraer los parámetros de POJO, pero para reemplazar fácilmente los marcadores de posición en una cadena?

Sé que sería posible rodar el mío, usando BeanUtils u otras bibliotecas con características similares, pero no quería reinventar la rueda.

Me gustaría tomar una cadena de la siguiente manera:

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

Y pasando una instancia de la clase de usuario a continuación:

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

A algo como:

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

Reemplazaría cada marcador de posición con valores reales.

¿Alguna idea?

¿Fue útil?

Solución

Rodar tu propio uso de BeanUtils no requeriría demasiada reinvención de la rueda (suponiendo que desees que sea tan básico como se solicita). Esta implementación toma un Mapa para el contexto de reemplazo, donde la clave del mapa debe corresponder a la primera parte de las rutas de búsqueda de variables dadas para el reemplazo.

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 las variables proporcionadas en su pregunta:

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

Otros consejos

Consulte la respuesta a esta pregunta similar sobre usando Lenguaje de expresión en un contexto independiente .

Spring Framework debería tener una función que haga esto (consulte el ejemplo de Spring JDBC a continuación). Si puede usar groovy (solo agregue el archivo groovy.jar) puede usar la función GString de Groovy para hacer esto bastante bien.

Ejemplo Groovy

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

Spring JDBC tiene una característica que uso para admitir variables de vinculación nombradas y anidadas de beans como este:

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

Su ejemplo de cadena es una plantilla válida en al menos algunos motores de plantillas, como Velocity o Freemarker. Estas bibliotecas ofrecen una forma de combinar una plantilla con un contexto que contiene algunos objetos (como "usuario" en su ejemplo).

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

Algún código de ejemplo (del sitio de 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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top