Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Several changes to enable el 2.2 replacement on existing solution and a new feature #92

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ boolean contains(Feature feature) {
*/
public static final String PROP_CACHE_SIZE = "javax.el.cacheSize";

/**
* <code>javax.el.cacheSize</code>
*/
public static final String PROP_CACHE_SIZE_FAIL_ON_RESIZE = "javax.el.cacheSize.failOnResize";

private final TreeStore store;
private final TypeConverter converter;

Expand Down Expand Up @@ -343,6 +348,7 @@ protected TreeStore createTreeStore(int defaultCacheSize, Profile profile, Prope
}

// create cache
Cache cache = null;
int cacheSize = defaultCacheSize;
if (properties != null && properties.containsKey(PROP_CACHE_SIZE)) {
try {
Expand All @@ -351,7 +357,16 @@ protected TreeStore createTreeStore(int defaultCacheSize, Profile profile, Prope
throw new ELException("Cannot parse EL property " + PROP_CACHE_SIZE, e);
}
}
Cache cache = cacheSize > 0 ? new Cache(cacheSize) : null;
if (properties != null && properties.containsKey(PROP_CACHE_SIZE_FAIL_ON_RESIZE)) {
try {
boolean failOnCacheResize = Boolean.parseBoolean(properties.getProperty(PROP_CACHE_SIZE_FAIL_ON_RESIZE));
cache = cacheSize > 0 ? new Cache(cacheSize, failOnCacheResize) : null;
} catch (NumberFormatException e) {
throw new ELException("Cannot parse EL property " + PROP_CACHE_SIZE, e);
}
}else{
cache = cacheSize > 0 ? new Cache(cacheSize) : null;
}

return new TreeStore(builder, cache);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.util.Date;

import javax.el.ELContext;
import javax.el.ELException;
Expand All @@ -33,6 +34,8 @@
import de.odysseus.el.tree.Tree;
import de.odysseus.el.tree.TreeBuilder;
import de.odysseus.el.tree.TreeStore;
import de.odysseus.el.tree.impl.ast.AstObject;
import de.odysseus.el.tree.impl.ast.AstTextForNull;

/**
* A value expression is ready to be evaluated (by calling either
Expand Down Expand Up @@ -73,14 +76,22 @@ public TreeValueExpression(TreeStore store, FunctionMapper functions, VariableMa
this.bindings = tree.bind(functions, variables, converter);
this.expr = expr;
this.type = type;
this.node = tree.getRoot();
this.node = getRootBasedOnType(tree, type);
this.deferred = tree.isDeferred();

if (type == null) {
throw new NullPointerException(LocalMessages.get("error.value.notype"));
}
}

private ExpressionNode getRootBasedOnType(Tree tree, Class<?> type) {
ExpressionNode expressionNode = tree.getRoot();
if(expressionNode instanceof AstTextForNull && type != String.class){
return new AstObject("");
}
return tree.getRoot();
}

private String getStructuralId() {
if (structure == null) {
structure = node.getStructuralId(bindings);
Expand Down
10 changes: 10 additions & 0 deletions modules/impl/src/main/java/de/odysseus/el/tree/impl/Cache.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public final class Cache implements TreeCache {
private final ConcurrentLinkedQueue<String> queue;
private final AtomicInteger size;
private final int capacity;
private boolean failOnResize;

/**
* Creates a new cache with the specified capacity
Expand All @@ -45,6 +46,12 @@ public final class Cache implements TreeCache {
*/
public Cache(int capacity) {
this(capacity, 16);
this.failOnResize = false;
}

public Cache(int capacity, boolean failOnResize) {
this(capacity, 16);
this.failOnResize = failOnResize;
}

/**
Expand Down Expand Up @@ -76,6 +83,9 @@ public void put(String expression, Tree tree) {
if (map.putIfAbsent(expression, tree) == null) {
queue.offer(expression);
if (size.incrementAndGet() > capacity) {
if(failOnResize){
throw new IllegalMonitorStateException("Resize occured for capacity:"+capacity);
}
size.decrementAndGet();
map.remove(queue.poll());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ public Tree tree() throws ScanException, ParseException {
AstNode t = text();
if (token.getSymbol() == EOF) {
if (t == null) {
t = new AstText("");
t = new AstTextForNull("");
}
return new Tree(t, functions, identifiers, false);
}
Expand Down
101 changes: 101 additions & 0 deletions modules/impl/src/main/java/de/odysseus/el/tree/impl/ast/AstObject.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright 2006-2009 Odysseus Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.odysseus.el.tree.impl.ast;

import de.odysseus.el.misc.LocalMessages;
import de.odysseus.el.tree.Bindings;

import javax.el.ELContext;
import javax.el.ELException;
import javax.el.MethodInfo;
import javax.el.ValueReference;

public class AstObject extends AstNode {
private final String value;

public AstObject(String value) {
this.value = value;
}

public boolean isLiteralText() {
return false;
}

public boolean isLeftValue() {
return false;
}

public boolean isMethodInvocation() {
return false;
}

public Class<?> getType(Bindings bindings, ELContext context) {
return null;
}

public boolean isReadOnly(Bindings bindings, ELContext context) {
return true;
}

public void setValue(Bindings bindings, ELContext context, Object value) {
throw new ELException(LocalMessages.get("error.value.set.rvalue", getStructuralId(bindings)));
}

public ValueReference getValueReference(Bindings bindings, ELContext context) {
return null;
}

@Override
public Object eval(Bindings bindings, ELContext context) {
return value;
}

public MethodInfo getMethodInfo(Bindings bindings, ELContext context, Class<?> returnType, Class<?>[] paramTypes) {
return null;
}

public Object invoke(Bindings bindings, ELContext context, Class<?> returnType, Class<?>[] paramTypes, Object[] paramValues) {
return returnType == null ? value : bindings.convert(value, returnType);
}

@Override
public String toString() {
return "\"" + value + "\"";
}

@Override
public void appendStructure(StringBuilder b, Bindings bindings) {
int end = value.length() - 1;
for (int i = 0; i < end; i++) {
char c = value.charAt(i);
if ((c == '#' || c == '$') && value.charAt(i + 1) == '{') {
b.append('\\');
}
b.append(c);
}
if (end >= 0) {
b.append(value.charAt(end));
}
}

public int getCardinality() {
return 0;
}

public AstNode getChild(int i) {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,20 @@ protected Method findMethod(String name, Class<?> clazz, Class<?> returnType, Cl
if (method == null) {
throw new MethodNotFoundException(LocalMessages.get("error.property.method.notfound", name, clazz));
}
if (!ignoreReturnType && returnType != null && !returnType.isAssignableFrom(method.getReturnType())) {
if (!ignoreReturnType && returnType != null
&& !isReturnTypeSame(returnType, method)) {
throw new MethodNotFoundException(LocalMessages.get("error.property.method.returntype", method.getReturnType(), name, clazz, returnType));
}
return method;
}


private boolean isReturnTypeSame(Class<?> returnType, Method method) {
if(java.lang.Void.class == returnType){
return true;
}
return returnType.isAssignableFrom(method.getReturnType());
}

public MethodInfo getMethodInfo(Bindings bindings, ELContext context, Class<?> returnType, Class<?>[] paramTypes) {
Object base = prefix.eval(bindings, context);
if (base == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import de.odysseus.el.misc.LocalMessages;
import de.odysseus.el.tree.Bindings;

public final class AstText extends AstNode {
public class AstText extends AstNode {
private final String value;

public AstText(String value) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package de.odysseus.el.tree.impl.ast;

/**
* Created by alexbrob on 2016-03-14.
*/
public final class AstTextForNull extends AstText {
public AstTextForNull(String value) {
super(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ public int bar() {
return 0;
}

public void voidMethod(){

}

SimpleContext context;
TreeStore store = new TreeStore(new Builder(Feature.METHOD_INVOCATIONS), null);

Expand Down Expand Up @@ -83,6 +87,15 @@ public void testInvoke() {
assertEquals(0, new TreeMethodExpression(store, null, null, null, "${base.foo()}", null, null).invoke(context, null));
}

public void testInvokeVoid() {
assertEquals(null, new TreeMethodExpression(store, null, null, null, "#{base.voidMethod}", Void.TYPE, new Class[0]).invoke(context, null));
assertEquals(null, new TreeMethodExpression(store, null, null, null, "#{base.voidMethod}", Void.class, new Class[0]).invoke(context, null));
assertEquals(null, new TreeMethodExpression(store, null, null, null, "#{base.voidMethod()}", null, null).invoke(context, null));

// TODO: Should this only be supported via the returnType flag?
// assertEquals(null, new TreeMethodExpression(store, null, null, null, "#{base.voidMethod}", Object.class, new Class[0]).invoke(context, null));
}


public void testSerialize() throws Exception {
TreeMethodExpression expression = new TreeMethodExpression(store, null, null, null, "${base.foo}", null, new Class[0]);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package de.odysseus.el.tree.impl.ast;

import de.odysseus.el.ObjectValueExpression;
import de.odysseus.el.TestCase;
import de.odysseus.el.TreeValueExpression;
import de.odysseus.el.misc.TypeConverter;
import de.odysseus.el.tree.TreeStore;
import de.odysseus.el.util.SimpleContext;
import de.odysseus.el.util.SimpleResolver;

import javax.el.MethodExpression;
import java.lang.reflect.Method;
import java.util.Date;

/**
* Created by alexbrob on 2016-03-14.
*/
public class AstDateTest extends TestCase {

SimpleContext context;

@Override
protected void setUp() throws Exception {
context = new SimpleContext(new SimpleResolver());

TypeConverter converter = TypeConverter.DEFAULT;

context.setVariable("var_date_1", new TreeValueExpression(new TreeStore(BUILDER, null), null, context.getVariableMapper(), converter, "", Date.class));
context.setVariable("var_string_1", new TreeValueExpression(new TreeStore(BUILDER, null), null, context.getVariableMapper(), converter, "", String.class));
}

public void testIsLiteralTextFalseForDate() throws Exception {
assertFalse(context.getVariableMapper().resolveVariable("var_date_1").isLiteralText());
}

public void testIsLiteralTextTrueForString() throws Exception {
assertTrue(context.getVariableMapper().resolveVariable("var_string_1").isLiteralText());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;

import javax.el.ELContext;
import javax.el.ELException;
Expand Down Expand Up @@ -91,6 +92,7 @@ protected void setUp() throws Exception {

// variables var_long_1, indentifier_string
context.setVariable("var_long_1", new ObjectValueExpression(converter, 1l, long.class));

context.setVariable("indentifier_string", new ObjectValueExpression(converter, "foo", String.class));
context.setVariable("var_method_1", new ObjectValueExpression(converter, getClass().getMethod("method_1"), Method.class));
context.setVariable("var_method_1_expr", new ObjectValueExpression(converter, new TestMethodExpression(getClass().getMethod("method_1")), MethodExpression.class));
Expand All @@ -103,7 +105,8 @@ protected void setUp() throws Exception {

// var_var_long_1 --> var_long_1, var_property_long_1 --> property_long_1
context.setVariable("var_var_long_1", new TreeValueExpression(new TreeStore(BUILDER, null), null, context.getVariableMapper(), null, "${var_long_1}", long.class));
context.setVariable("var_property_long_1", new TreeValueExpression(new TreeStore(BUILDER, null), null, context.getVariableMapper(), null, "${property_long_1}", long.class));
context.setVariable("var_property_long_1", new TreeValueExpression(new TreeStore(BUILDER, null), null, context.getVariableMapper(), null, "${property_long_1}", long.class));
context.setVariable("var_date_1", new TreeValueExpression(new TreeStore(BUILDER, null), null, context.getVariableMapper(), converter, "", Date.class));
}

public void testEval() {
Expand Down Expand Up @@ -141,6 +144,10 @@ public void testAppendStructure() {
assertEquals("foo", s.toString());
}

public void testIsLiteralTextFalseForDate() throws Exception {
assertFalse(context.getVariableMapper().resolveVariable("var_date_1").isLiteralText());
}

public void testIsLiteralText() {
assertFalse(parseNode("${foo}").isLiteralText());
}
Expand Down