Skip to content

Commit

Permalink
refs #89 EL2とEL3の実装を分離しNoClassDefFoundErrorが発生する事象を修正
Browse files Browse the repository at this point in the history
  • Loading branch information
mygreen committed Dec 23, 2016
1 parent fed3e6c commit 4e04085
Show file tree
Hide file tree
Showing 9 changed files with 875 additions and 333 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.gh.mygreen.xlsmapper.expression;

import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;

import org.hibernate.validator.internal.engine.messageinterpolation.el.RootResolver;

import com.github.mygreen.expression.el.FormatterWrapper;
import com.github.mygreen.expression.el.tld.Taglib;
import com.github.mygreen.expression.el.tld.TldLoader;

/**
* EL式を利用する際のベースとなる抽象クラス。
*
* @since 1.6
* @author T.TSUCHIE
*
*/
public abstract class AbstractExpressionLanguageEL implements ExpressionLanguage {

/** TLDファイルの定義内容 */
protected List<Taglib> taglibList = new ArrayList<>();

/**
* カスタムタグの定義ファイル「TLD(Tag Library Defenitioin)」を登録する。
* <p>{@link TldLoader}クラスで読み込む。
*
* @since 1.5
* @param taglib カスタムタグの定義内容。
*/
public void register(final Taglib taglib) {
this.taglibList.add(taglib);
}

/**
* 登録されているEL式中の変数(Bean)が、{@link Formatter}かどうか判定する。
* <p>{@link Formatter}中のメソッド{@code format(...)}メソッドは、オーバロードで複数のメソッドが定義されいるが、
* EL式はメソッドのオーバーロードはサポートされていない。
* <br>そのため、{@link FormatterWrapper}でラップして、オーバーロードなしのメソッドする。
* </p>
* @param key 判定対象のキー値
* @param value 判定対象の値のインスタンス
* @return キー名が{@link RootResolver#FORMATTER}(formatter)と一致し、かつ、valueのインスタンスが{@link Formatter}の場合、trueを返します。
*/
protected boolean isFormatter(final String key, final Object value) {
if(!RootResolver.FORMATTER.equals(key)) {
return false;
}

if(value instanceof Formatter) {
return true;
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.gh.mygreen.xlsmapper.expression;

import java.util.Formatter;
import java.util.Map;
import java.util.Map.Entry;

import javax.el.ELException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gh.mygreen.xlsmapper.ArgUtils;
import com.gh.mygreen.xlsmapper.Utils;
import com.github.mygreen.expression.el.ELProcessor;
import com.github.mygreen.expression.el.FormatterWrapper;
import com.github.mygreen.expression.el.tld.Function;
import com.github.mygreen.expression.el.tld.Taglib;

/**
* EL式(EL 2.x)を使用するための実装。
*
* @since 1.6
* @author T.TSUCHIE
*
*/
public class ExpressionLangaugeEL2Impl extends AbstractExpressionLanguageEL {

private static final Logger logger = LoggerFactory.getLogger(ExpressionLangaugeEL2Impl.class);

@Override
public Object evaluate(final String expression, final Map<String, ?> values) {

ArgUtils.notEmpty(expression, "expression");
ArgUtils.notNull(values, "values");

try {
final ELProcessor elProc = new ELProcessor();

for (final Entry<String, ? > entry : values.entrySet()) {
if(isFormatter(entry.getKey(), entry.getValue())) {
elProc.setVariable(entry.getKey(), new FormatterWrapper((Formatter) entry.getValue()));
} else {
elProc.setVariable(entry.getKey(), entry.getValue());
}
}

// カスタムタグを登録する。
for(Taglib taglib : taglibList) {
final String prefix = Utils.trimToEmpty(taglib.getShortName());

for(Function function : taglib.getFunctions()) {
final String className = Utils.trimToEmpty(function.getFunctionClass());
final String signature = Utils.trimToEmpty(function.getFunctionSignature());
final String name = Utils.trimToEmpty(function.getName());

try {
elProc.defineFunction(prefix, name, className, signature);

} catch(ClassNotFoundException | NoSuchMethodException ex) {
throw new ExpressionEvaluationException(String.format("Faild defined with EL function : [%s:%s].", className, signature), ex);
}
}
}

if(logger.isDebugEnabled()) {
logger.debug("Evaluating EL expression: {}", expression);
}

return elProc.eval(expression);

} catch (final ELException ex){
throw new ExpressionEvaluationException(String.format("Evaluating [%s] script with EL failed.", expression), ex);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.gh.mygreen.xlsmapper.expression;

import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.el.BeanNameResolver;
import javax.el.ELException;
import javax.el.ELProcessor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gh.mygreen.xlsmapper.ArgUtils;
import com.gh.mygreen.xlsmapper.Utils;
import com.github.mygreen.expression.el.FormatterWrapper;
import com.github.mygreen.expression.el.tld.Function;
import com.github.mygreen.expression.el.tld.Taglib;

/**
* EL式(EL 3.x)を使用するための実装。
*
* @since 1.6
* @author T.TSUCHIE
*
*/
public class ExpressionLangaugeEL3Impl extends AbstractExpressionLanguageEL {

private static final Logger logger = LoggerFactory.getLogger(ExpressionLangaugeEL3Impl.class);

@Override
public Object evaluate(final String expression, final Map<String, ?> values) {

ArgUtils.notEmpty(expression, "expression");
ArgUtils.notNull(values, "values");

try {
final ELProcessor elProc = new ELProcessor();

final Map<String, Object> beans = new HashMap<String, Object>();
for (final Entry<String, ? > entry : values.entrySet()) {
if(isFormatter(entry.getKey(), entry.getValue())) {
// Formatterの場合は、ラップクラスを設定する。
beans.put(entry.getKey(), new FormatterWrapper((Formatter) entry.getValue()));
} else {
beans.put(entry.getKey(), entry.getValue());
}
}

elProc.getELManager().addBeanNameResolver(new LocalBeanNameResolver(beans));

// カスタムタグを登録する。
for(Taglib taglib : taglibList) {
final String prefix = Utils.trimToEmpty(taglib.getShortName());

for(Function function : taglib.getFunctions()) {
final String className = Utils.trimToEmpty(function.getFunctionClass());
final String signature = Utils.trimToEmpty(function.getFunctionSignature());
final String name = Utils.trimToEmpty(function.getName());

try {
elProc.defineFunction(prefix, name, className, signature);

} catch(ClassNotFoundException | NoSuchMethodException ex) {
throw new ExpressionEvaluationException(String.format("Faild defined with EL function : [%s:%s].", className, signature), ex);
}
}
}

if(logger.isDebugEnabled()) {
logger.debug("Evaluating EL expression: {}", expression);
}

return elProc.eval(expression);

} catch (final ELException ex){
throw new ExpressionEvaluationException(String.format("Evaluating [%s] script with EL failed.", expression), ex);
}
}

/**
* EL3.0用の式中の変数のResolver。
* ・存在しない場合はnullを返す。
*
*/
private class LocalBeanNameResolver extends BeanNameResolver {

private final Map<String, Object> map;

public LocalBeanNameResolver(final Map<String, ?> map) {
this.map = new HashMap<>(map);
}

@Override
public boolean isNameResolved(final String beanName){
// 存在しない場合はnullを返すように、必ずtrueを設定する。
return true;
}

@Override
public Object getBean(final String beanName){
return map.get( beanName );
}

@Override
public void setBeanValue(String beanName, Object value){
map.put(beanName, value );
}

}

}

0 comments on commit 4e04085

Please sign in to comment.