“ BeanUtilsを同様に使用する最も簡単な方法”取り替える
-
02-07-2019 - |
質問
POJOパラメータを抽出するためにBeanUtilsで使用するのと同じ既知の表記法を使用できるが、文字列のプレースホルダーを簡単に置き換えることができるライブラリはありますか?
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クラスの1つのインスタンスを渡します:
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));
各プレースホルダーを実際の値に置き換えます。
アイデアはありますか
解決
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));
他のヒント
Spring Frameworkには、これを行う機能が必要です(以下のSpring JDBCの例を参照)。 groovyを使用できる場合(groovy.jarファイルを追加するだけ)、GroovyのGString機能を使用してこれを非常にうまく行うことができます。
Groovyの例
foxtype = 'quick'
foxcolor = ['b', 'r', 'o', 'w', 'n']
println "The $foxtype ${foxcolor.join()} fox"
Spring JDBCには、次のようなBeanの名前付きおよびネストされた名前付きバインド変数をサポートするために使用する機能があります。
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);
}
文字列の例は、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();