Domanda

Esistono librerie che mi permetterebbero di usare la stessa notazione nota che usiamo in BeanUtils per estrarre i parametri POJO, ma per sostituire facilmente i segnaposto in una stringa?

So che sarebbe possibile realizzare il mio, usando BeanUtils stesso o altre librerie con caratteristiche simili, ma non volevo reinventare la ruota.

Vorrei prendere una stringa come 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 un'istanza della classe User di seguito:

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 qualcosa di simile:

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

Sostituirebbe ogni segnaposto con i valori effettivi.

Qualche idea?

È stato utile?

Soluzione

Rotolare il tuo usando BeanUtils non richiederebbe troppa reinvenzione delle ruote (supponendo che tu voglia che sia basilare come richiesto). Questa implementazione utilizza una mappa per il contesto di sostituzione, in cui la chiave della mappa deve corrispondere alla prima parte dei percorsi di ricerca variabili forniti per la sostituzione.

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

Date le variabili fornite nella tua domanda:

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

Altri suggerimenti

Vedi la risposta a questa domanda simile su utilizzando Linguaggio di espressione in un contesto autonomo .

Spring Framework dovrebbe avere una funzione che faccia questo (vedi l'esempio JDBC di Spring di seguito). Se puoi usare groovy (basta aggiungere il file groovy.jar) puoi usare la funzione GString di Groovy per farlo abbastanza bene.

Esempio Groovy

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

Spring JDBC ha una funzione che uso per supportare variabili di bind nominate nominate e nidificate da bean in questo modo:

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

Il tuo esempio di stringa è un modello valido in almeno alcuni motori di template, come Velocity o Freemarker. Queste librerie offrono un modo per unire un modello con un contesto contenente alcuni oggetti (come "utente" nel tuo esempio).

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

Alcuni esempi di codice (dal sito 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();
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top