blob: 566429f9e2690a554885fab9aa0285039dea77ed [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 com.opensymphony.xwork2.ognl;
import com.opensymphony.xwork2.*;
import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.ContainerBuilder;
import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
import com.opensymphony.xwork2.test.StubConfigurationProvider;
import com.opensymphony.xwork2.test.TestBean2;
import com.opensymphony.xwork2.util.*;
import com.opensymphony.xwork2.util.Foo;
import com.opensymphony.xwork2.util.location.LocatableProperties;
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
import ognl.OgnlException;
import ognl.PropertyAccessor;
import java.io.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import ognl.ParseException;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.config.DefaultPropertiesProvider;
/**
* Unit test for OgnlValueStack.
*/
public class OgnlValueStackTest extends XWorkTestCase {
// Fields for static field access test
public static final String STATIC_FINAL_PUBLIC_ATTRIBUTE = "Static_Final_Public_Attribute";
static final String STATIC_FINAL_PACKAGE_ATTRIBUTE = "Static_Final_Package_Attribute";
protected static final String STATIC_FINAL_PROTECTED_ATTRIBUTE = "Static_Final_Protected_Attribute";
private static final String STATIC_FINAL_PRIVATE_ATTRIBUTE = "Static_Final_Private_Attribute";
public static String STATIC_PUBLIC_ATTRIBUTE = "Static_Public_Attribute";
static String STATIC_PACKAGE_ATTRIBUTE = "Static_Package_Attribute";
protected static String STATIC_PROTECTED_ATTRIBUTE = "Static_Protected_Attribute";
private static String STATIC_PRIVATE_ATTRIBUTE = "Static_Private_Attribute";
public static Integer staticNullMethod() {
return null;
}
public static Integer staticInteger100Method() {
return 100;
}
private OgnlUtil ognlUtil;
@Override
public void setUp() throws Exception {
super.setUp();
ognlUtil = container.getInstance(OgnlUtil.class);
}
private OgnlValueStack createValueStack() {
return createValueStack(true);
}
private OgnlValueStack createValueStack(boolean allowStaticMethodAccess) {
OgnlValueStack stack = new OgnlValueStack(
container.getInstance(XWorkConverter.class),
(CompoundRootAccessor) container.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()),
container.getInstance(TextProvider.class, "system"), allowStaticMethodAccess);
container.inject(stack);
ognlUtil.setAllowStaticMethodAccess(Boolean.toString(allowStaticMethodAccess));
return stack;
}
/**
* @return current OgnlValueStackFactory instance from current container
*/
private OgnlValueStackFactory getValueStackFactory() {
return (OgnlValueStackFactory) container.getInstance(ValueStackFactory.class);
}
/**
* Reloads container and gets a new OgnlValueStackFactory with specified new configuration.
* Intended for testing OgnlValueStack instance(s) that are minimally configured.
* This should help ensure no underlying configuration/injection side-effects are responsible
* for the behaviour of fundamental access control flags).
*
* @param allowStaticMethod new allowStaticMethod configuration
* @return a new OgnlValueStackFactory with specified new configuration
*/
private OgnlValueStackFactory reloadValueStackFactory(Boolean allowStaticMethod) {
try {
reloadTestContainerConfiguration(allowStaticMethod);
}
catch (Exception ex) {
fail("Unable to reload container configuration and configure ognlValueStackFactory - exception: " + ex);
}
return getValueStackFactory();
}
public void testExpOverridesCanStackExpUp() throws Exception {
Map expr1 = new LinkedHashMap();
expr1.put("expr1", "'expr1value'");
OgnlValueStack vs = createValueStack();
vs.setExprOverrides(expr1);
assertEquals(vs.findValue("expr1"), "expr1value");
Map expr2 = new LinkedHashMap();
expr2.put("expr2", "'expr2value'");
expr2.put("expr3", "'expr3value'");
vs.setExprOverrides(expr2);
assertEquals(vs.findValue("expr2"), "expr2value");
assertEquals(vs.findValue("expr3"), "expr3value");
}
public void testArrayAsString() {
OgnlValueStack vs = createValueStack();
Dog dog = new Dog();
dog.setAge(12);
dog.setName("Rover");
dog.setChildAges(new int[]{1, 2});
vs.push(dog);
assertEquals("1, 2", vs.findValue("childAges", String.class));
}
public void testValuesFromContextAreConverted() {
testValuesFromContextAreConverted("dogName");
testValuesFromContextAreConverted("dog.name");
}
private void testValuesFromContextAreConverted(String propertyName) {
final OgnlValueStack vs = createValueStack();
final String propertyValue = "Rover";
vs.getContext().put(propertyName, new String[]{propertyValue});
assertEquals(propertyValue, vs.findValue(propertyName, String.class));
}
public void testNullValueFromContextGetsConverted() {
testNullValueFromContextGetsConverted("dogName");
testNullValueFromContextGetsConverted("dog.name");
}
private void testNullValueFromContextGetsConverted(String propertyName) {
final OgnlValueStack vs = createValueStack();
final String propertyValue = null;
vs.getContext().put(propertyName, propertyValue);
assertEquals(propertyValue, vs.findValue(propertyName, String.class));
}
public void testFailOnException() {
OgnlValueStack vs = createValueStack();
Dog dog = new Dog();
vs.push(dog);
try {
vs.findValue("bite", true);
fail("Failed to throw exception on EL error");
} catch (Exception ex) {
//ok
}
}
public void testFailOnErrorOnInheritedProperties() {
//this shuld not fail as the property is defined on a parent class
OgnlValueStack vs = createValueStack();
Foo foo = new Foo();
BarJunior barjr = new BarJunior();
foo.setBarJunior(barjr);
vs.push(foo);
assertNull(barjr.getTitle());
vs.findValue("barJunior.title", true);
}
public void testSuccessFailOnErrorOnInheritedPropertiesWithMethods() {
//this shuld not fail as the property is defined on a parent class
OgnlValueStack vs = createValueStack();
Foo foo = new Foo();
BarJunior barjr = new BarJunior();
foo.setBarJunior(barjr);
vs.push(foo);
assertNull(barjr.getTitle());
vs.findValue("getBarJunior().title", true);
}
public void testFailFailOnErrorOnInheritedPropertiesWithMethods() {
OgnlValueStack vs = createValueStack();
Foo foo = new Foo();
BarJunior barjr = new BarJunior();
foo.setBarJunior(barjr);
vs.push(foo);
assertNull(barjr.getTitle());
try {
vs.findValue("getBarJunior().title2", true);
fail("should have failed on missing property");
} catch (Exception e) {
}
}
public void testFailOnMissingProperty() {
OgnlValueStack vs = createValueStack();
Dog dog = new Dog();
vs.push(dog);
try {
vs.findValue("someprop", true);
fail("Failed to throw exception on EL missing property");
} catch (Exception ex) {
//ok
}
}
/**
* monitors the resolution of WW-4999
* @since 2.5.21
*/
public void testLogMissingProperties() {
testLogMissingProperties(true);
testLogMissingProperties(false);
}
private void testLogMissingProperties(boolean logMissingProperties) {
OgnlValueStack vs = createValueStack();
vs.setLogMissingProperties("" + logMissingProperties);
Dog dog = new Dog();
vs.push(dog);
TestAppender testAppender = new TestAppender();
Logger logger = (Logger) LogManager.getLogger(OgnlValueStack.class);
logger.addAppender(testAppender);
testAppender.start();
try {
vs.setValue("missingProp1", "missingProp1Value", false);
vs.findValue("missingProp2", false);
vs.findValue("missingProp3", Integer.class, false);
if (logMissingProperties) {
assertEquals(3, testAppender.logEvents.size());
assertEquals("Error setting value [missingProp1Value] with expression [missingProp1]",
testAppender.logEvents.get(0).getMessage().getFormattedMessage());
assertEquals("Could not find property [missingProp2]!",
testAppender.logEvents.get(1).getMessage().getFormattedMessage());
assertEquals("Could not find property [missingProp3]!",
testAppender.logEvents.get(2).getMessage().getFormattedMessage());
} else {
assertEquals(0, testAppender.logEvents.size());
}
} finally {
testAppender.stop();
logger.removeAppender(testAppender);
}
}
/**
* tests the correctness of distinguishing between user exception and NoSuchMethodException
* @since 2.5.21
*/
public void testNotLogUserExceptionsAsMissingProperties() {
OgnlValueStack vs = createValueStack();
vs.setLogMissingProperties("true");
Dog dog = new Dog();
vs.push(dog);
TestAppender testAppender = new TestAppender();
Logger logger = (Logger) LogManager.getLogger(OgnlValueStack.class);
logger.addAppender(testAppender);
testAppender.start();
try {
vs.setValue("exception", "exceptionValue", false);
vs.findValue("exception", false);
vs.findValue("exception", String.class, false);
vs.findValue("getException()", false);
vs.findValue("getException()", String.class, false);
vs.findValue("bite", false);
vs.findValue("bite", void.class, false);
vs.findValue("getBite()", false);
vs.findValue("getBite()", void.class, false);
vs.setLogMissingProperties("false");
vs.setValue("exception", "exceptionValue", false);
vs.findValue("exception", false);
vs.findValue("exception", String.class, false);
vs.findValue("getException()", false);
vs.findValue("getException()", String.class, false);
vs.findValue("bite", false);
vs.findValue("bite", void.class, false);
vs.findValue("getBite()", false);
vs.findValue("getBite()", void.class, false);
assertEquals(0, testAppender.logEvents.size());
} finally {
testAppender.stop();
logger.removeAppender(testAppender);
}
}
public void testFailOnMissingMethod() {
OgnlValueStack vs = createValueStack();
Dog dog = new Dog();
vs.push(dog);
try {
vs.findValue("someprop()", true);
fail("Failed to throw exception on EL missing method");
} catch (Exception ex) {
//ok
}
}
public void testFailOnTooLongExpressionLongerThan192_ViaOverriddenProperty() {
try {
loadConfigurationProviders(new StubConfigurationProvider() {
@Override
public void register(ContainerBuilder builder,
LocatableProperties props) throws ConfigurationException {
props.setProperty(StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH, "192");
}
});
Integer repeat = Integer.parseInt(
container.getInstance(String.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH));
OgnlValueStack vs = createValueStack();
try {
vs.findValue(StringUtils.repeat('.', repeat + 1), true);
fail("Failed to throw exception on too long expression");
} catch (Exception ex) {
assertTrue(ex.getCause() instanceof OgnlException);
assertTrue(((OgnlException) ex.getCause()).getReason() instanceof SecurityException);
}
} finally {
// Reset expressionMaxLength value to default (disabled)
ognlUtil.applyExpressionMaxLength(null);
}
}
public void testNotFailOnTooLongExpressionWithDefaultProperties() {
loadConfigurationProviders(new DefaultPropertiesProvider());
Object defaultMaxLengthFromConfiguration = container.getInstance(String.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH);
if (defaultMaxLengthFromConfiguration != null) {
assertTrue("non-null defaultMaxLengthFromConfiguration not a String ?", defaultMaxLengthFromConfiguration instanceof String);
assertTrue("non-null defaultMaxLengthFromConfiguration not empty string by default ?", ((String) defaultMaxLengthFromConfiguration).length() == 0);
} else {
assertNull("defaultMaxLengthFromConfiguration not null ?", defaultMaxLengthFromConfiguration);
}
// Original test logic was to confirm failure of exceeding the default value. Now the feature should be disabled by default,
// so this test's expectations are now changed.
Integer repeat = Integer.valueOf(256); // Since maxlength is disabled by default, just choose an arbitrary value for test
OgnlValueStack vs = createValueStack();
try {
vs.findValue(StringUtils.repeat('.', repeat + 1), true);
fail("findValue did not throw any exception (should either fail as invalid expression syntax or security exception) ?");
} catch (Exception ex) {
// If STRUTS_OGNL_EXPRESSION_MAX_LENGTH feature is disabled (default), the parse should fail due to a reason of invalid expression syntax
// with ParseException. Previously when it was enabled the reason for the failure would have been SecurityException.
assertTrue(ex.getCause() instanceof OgnlException);
assertTrue(((OgnlException) ex.getCause()).getReason() instanceof ParseException);
}
}
public void testNotFailOnTooLongValueWithDefaultProperties() {
try {
loadConfigurationProviders(new DefaultPropertiesProvider());
Object defaultMaxLengthFromConfiguration = container.getInstance(String.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH);
if (defaultMaxLengthFromConfiguration != null) {
assertTrue("non-null defaultMaxLengthFromConfiguration not a String ?", defaultMaxLengthFromConfiguration instanceof String);
assertTrue("non-null defaultMaxLengthFromConfiguration not empty string by default ?", ((String) defaultMaxLengthFromConfiguration).length() == 0);
} else {
assertNull("defaultMaxLengthFromConfiguration not null ?", defaultMaxLengthFromConfiguration);
}
// Original test logic is unchanged (testing that values can be larger than maximum expression length), but since the feature is disabled by
// default we will now have to enable it with an arbitrary value, test, and reset it to disabled.
Integer repeat = Integer.valueOf(256); // Since maxlength is disabled by default, just choose an arbitrary value for test
// Apply a non-default value for expressionMaxLength (as it should be disabled by default)
try {
ognlUtil.applyExpressionMaxLength(repeat.toString());
} catch (Exception ex) {
fail ("applyExpressionMaxLength did not accept maxlength string " + repeat.toString() + " ?");
}
OgnlValueStack vs = createValueStack();
Dog dog = new Dog();
vs.push(dog);
String value = StringUtils.repeat('.', repeat + 1);
vs.setValue("name", value);
assertEquals(value, dog.getName());
} finally {
// Reset expressionMaxLength value to default (disabled)
ognlUtil.applyExpressionMaxLength(null);
}
}
public void testFailsOnMethodThatThrowsException() {
SimpleAction action = new SimpleAction();
OgnlValueStack stack = createValueStack();
stack.push(action);
action.setThrowException(true);
try {
stack.findValue("exceptionMethod12()", true);
fail("Failed to throw exception on EL method exception");
} catch (Exception ex) {
//ok
}
}
public void testDoesNotFailOnNonActionObjects() {
//if a value is not found, then it will check for missing properties
//it needs to check in all objects in the stack, not only actions, see WW-3306
OgnlValueStack vs = createValueStack();
Dog dog = new Dog();
dog.setHates(null);
vs.push(dog);
vs.findValue("hates", true);
}
public void testFailOnMissingNestedProperty() {
OgnlValueStack vs = createValueStack();
Dog dog = new Dog();
dog.setHates(new Cat());
vs.push(dog);
try {
vs.findValue("hates.someprop", true);
fail("Failed to throw exception on EL missing nested property");
} catch (Exception ex) {
//ok
}
}
public void testBasic() {
OgnlValueStack vs = createValueStack();
Dog dog = new Dog();
dog.setAge(12);
dog.setName("Rover");
vs.push(dog);
assertEquals("Rover", vs.findValue("name", String.class));
}
public void testStatic() {
OgnlValueStack vs = createValueStack();
Dog dog = new Dog();
dog.setDeity("fido");
vs.push(dog);
assertEquals("fido", vs.findValue("@com.opensymphony.xwork2.util.Dog@getDeity()", String.class));
}
/**
* Allow access Enums without enabling access to static methods
*/
public void testEnum() throws Exception {
OgnlValueStack vs = createValueStack();
assertEquals("ONE", vs.findValue("@com.opensymphony.xwork2.ognl.MyNumbers@values()[0]", String.class));
assertEquals("TWO", vs.findValue("@com.opensymphony.xwork2.ognl.MyNumbers@values()[1]", String.class));
assertEquals("THREE", vs.findValue("@com.opensymphony.xwork2.ognl.MyNumbers@values()[2]", String.class));
}
public void testStaticMethodDisallow() {
OgnlValueStack vs = createValueStack(false);
Dog dog = new Dog();
dog.setDeity("fido");
vs.push(dog);
assertNull(vs.findValue("@com.opensymphony.xwork2.util.Dog@getDeity()", String.class));
}
public void testBasicSet() {
OgnlValueStack vs = createValueStack();
Dog dog = new Dog();
dog.setAge(12);
dog.setName("Rover");
vs.set("dog", dog);
assertEquals("Rover", vs.findValue("dog.name", String.class));
}
public void testCallMethodOnNullObject() {
OgnlValueStack stack = createValueStack();
assertNull(stack.findValue("foo.size()"));
}
public void testCallMethodThatThrowsExceptionTwice() {
SimpleAction action = new SimpleAction();
OgnlValueStack stack = createValueStack();
stack.push(action);
action.setThrowException(true);
assertNull(stack.findValue("exceptionMethod1()"));
action.setThrowException(false);
assertEquals("OK", stack.findValue("exceptionMethod()"));
}
public void testCallMethodWithNullArg() {
SimpleAction action = new SimpleAction();
OgnlValueStack stack = createValueStack();
stack.push(action);
stack.findValue("setName(blah)");
assertNull(action.getName());
action.setBlah("blah");
stack.findValue("setName(blah)");
assertEquals("blah", action.getName());
}
public void testConvertStringArrayToList() {
Foo foo = new Foo();
OgnlValueStack vs = createValueStack();
vs.push(foo);
vs.setValue("strings", new String[]{"one", "two"});
assertNotNull(foo.getStrings());
assertEquals("one", foo.getStrings().get(0));
assertEquals("two", foo.getStrings().get(1));
}
public void testFindValueWithConversion() {
// register converter
TestBean2 tb2 = new TestBean2();
OgnlValueStack stack = createValueStack();
stack.push(tb2);
Map myContext = stack.getContext();
Map props = new HashMap();
props.put("cat", "Kitty");
ognlUtil.setProperties(props, tb2, myContext);
// expect String to be converted into a Cat
assertEquals("Kitty", tb2.getCat().getName());
// findValue should be able to access the name
Object value = stack.findValue("cat.name == 'Kitty'", Boolean.class);
assertNotNull(value);
assertEquals(Boolean.class, value.getClass());
assertEquals(Boolean.TRUE, value);
value = stack.findValue("cat == null", Boolean.class);
assertNotNull(value);
assertEquals(Boolean.class, value.getClass());
assertEquals(Boolean.FALSE, value);
}
public void testDeepProperties() {
OgnlValueStack vs = createValueStack();
Cat cat = new Cat();
cat.setName("Smokey");
Dog dog = new Dog();
dog.setAge(12);
dog.setName("Rover");
dog.setChildAges(new int[]{1, 2});
dog.setHates(cat);
vs.push(dog);
assertEquals("Smokey", vs.findValue("hates.name", String.class));
}
public void testFooBarAsString() {
OgnlValueStack vs = createValueStack();
Foo foo = new Foo();
Bar bar = new Bar();
bar.setTitle("blah");
bar.setSomethingElse(123);
foo.setBar(bar);
vs.push(foo);
assertEquals("blah:123", vs.findValue("bar", String.class));
}
public void testGetBarAsString() {
Foo foo = new Foo();
Bar bar = new Bar();
bar.setTitle("bar");
bar.setSomethingElse(123);
foo.setBar(bar);
OgnlValueStack vs = createValueStack();
vs.push(foo);
String output = (String) vs.findValue("bar", String.class);
assertEquals("bar:123", output);
}
public void testGetComplexBarAsString() {
// children foo->foo->foo
Foo foo = new Foo();
Foo foo2 = new Foo();
foo.setChild(foo2);
Foo foo3 = new Foo();
foo2.setChild(foo3);
// relatives
Foo fooA = new Foo();
foo.setRelatives(new Foo[]{fooA});
Foo fooB = new Foo();
foo2.setRelatives(new Foo[]{fooB});
Foo fooC = new Foo();
foo3.setRelatives(new Foo[]{fooC});
// the bar
Bar bar = new Bar();
bar.setTitle("bar");
bar.setSomethingElse(123);
// now place the bar all over
foo.setBar(bar);
foo2.setBar(bar);
foo3.setBar(bar);
fooA.setBar(bar);
fooB.setBar(bar);
fooC.setBar(bar);
OgnlValueStack vs = createValueStack();
vs.push(foo);
vs.getContext().put("foo", foo);
assertEquals("bar:123", vs.findValue("#foo.bar", String.class));
assertEquals("bar:123", vs.findValue("bar", String.class));
assertEquals("bar:123", vs.findValue("child.bar", String.class));
assertEquals("bar:123", vs.findValue("child.child.bar", String.class));
assertEquals("bar:123", vs.findValue("relatives[0].bar", String.class));
assertEquals("bar:123", vs.findValue("child.relatives[0].bar", String.class));
assertEquals("bar:123", vs.findValue("child.child.relatives[0].bar", String.class));
vs.push(vs.findValue("child"));
assertEquals("bar:123", vs.findValue("bar", String.class));
assertEquals("bar:123", vs.findValue("child.bar", String.class));
assertEquals("bar:123", vs.findValue("relatives[0].bar", String.class));
assertEquals("bar:123", vs.findValue("child.relatives[0].bar", String.class));
}
public void testGetNullValue() {
Dog dog = new Dog();
OgnlValueStack stack = createValueStack();
stack.push(dog);
assertNull(stack.findValue("name"));
}
public void testMapEntriesAvailableByKey() {
Foo foo = new Foo();
String title = "a title";
foo.setTitle(title);
OgnlValueStack vs = createValueStack();
vs.push(foo);
Map map = new HashMap();
String a_key = "a";
String a_value = "A";
map.put(a_key, a_value);
String b_key = "b";
String b_value = "B";
map.put(b_key, b_value);
vs.push(map);
assertEquals(title, vs.findValue("title"));
assertEquals(a_value, vs.findValue(a_key));
assertEquals(b_value, vs.findValue(b_key));
}
public void testMethodCalls() {
OgnlValueStack vs = createValueStack();
Dog dog1 = new Dog();
dog1.setAge(12);
dog1.setName("Rover");
Dog dog2 = new Dog();
dog2.setAge(1);
dog2.setName("Jack");
vs.push(dog1);
vs.push(dog2);
//assertEquals(new Boolean(false), vs.findValue("'Rover'.endsWith('Jack')"));
//assertEquals(new Boolean(false), vs.findValue("'Rover'.endsWith(name)"));
//assertEquals("RoverJack", vs.findValue("[1].name + name"));
assertEquals(new Boolean(false), vs.findValue("[1].name.endsWith(name)"));
assertEquals(new Integer(1 * 7), vs.findValue("computeDogYears()"));
assertEquals(new Integer(1 * 2), vs.findValue("multiplyAge(2)"));
assertEquals(new Integer(12 * 7), vs.findValue("[1].computeDogYears()"));
assertEquals(new Integer(12 * 5), vs.findValue("[1].multiplyAge(5)"));
assertNull(vs.findValue("thisMethodIsBunk()"));
assertEquals(new Integer(12 * 1), vs.findValue("[1].multiplyAge(age)"));
assertEquals("Jack", vs.findValue("name"));
assertEquals("Rover", vs.findValue("[1].name"));
//hates will be null
assertEquals(Boolean.TRUE, vs.findValue("nullSafeMethod(hates)"));
}
public void testMismatchedGettersAndSettersCauseExceptionInSet() {
OgnlValueStack vs = createValueStack();
BadJavaBean bean = new BadJavaBean();
vs.push(bean);
//this used to fail in OGNl versdion < 2.7
vs.setValue("count", "1", true);
assertEquals("1", bean.getCount());
try {
vs.setValue("count2", "a", true);
fail("Expected an exception for mismatched getter and setter");
} catch (XWorkException e) {
//expected
}
}
public void testNoExceptionInSetForDefault() {
OgnlValueStack vs = createValueStack();
BadJavaBean bean = new BadJavaBean();
vs.push(bean);
//this used to fail in OGNl versdion < 2.7
vs.setValue("count", "1", true);
assertEquals("1", bean.getCount());
try {
vs.setValue("count2", "a", true);
fail("Expected an exception for mismatched getter and setter");
} catch (XWorkException e) {
//expected
}
}
public void testNullEntry() {
OgnlValueStack vs = createValueStack();
Dog dog = new Dog();
dog.setName("Rover");
vs.push(dog);
assertEquals("Rover", vs.findValue("name", String.class));
vs.push(null);
assertEquals("Rover", vs.findValue("name", String.class));
}
public void testNullMethod() {
Dog dog = new Dog();
OgnlValueStack stack = createValueStack();
stack.push(dog);
assertNull(stack.findValue("nullMethod()"));
assertNull(stack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticNullMethod()"));
}
public void testPetSoarBug() {
Cat cat = new Cat();
cat.setFoo(new Foo());
Bar bar = new Bar();
bar.setTitle("bar");
bar.setSomethingElse(123);
cat.getFoo().setBar(bar);
OgnlValueStack vs = createValueStack();
vs.push(cat);
assertEquals("bar:123", vs.findValue("foo.bar", String.class));
}
public void testPrimitiveSettingWithInvalidValueAddsFieldErrorInDevMode() throws Exception {
SimpleAction action = new SimpleAction();
OgnlValueStack stack = createValueStack();
stack.getContext().put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE);
stack.setDevMode("true");
stack.push(action);
try {
stack.setValue("bar", "3x");
fail("Attempt to set 'bar' int property to '3x' should result in RuntimeException");
}
catch (RuntimeException re) {
assertTrue(true);
}
Map conversionErrors = (Map) stack.getContext().get(ActionContext.CONVERSION_ERRORS);
assertTrue(conversionErrors.containsKey("bar"));
}
public void testPrimitiveSettingWithInvalidValueAddsFieldErrorInNonDevMode() throws Exception {
SimpleAction action = new SimpleAction();
OgnlValueStack stack = createValueStack();
stack.getContext().put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE);
stack.setDevMode("false");
stack.push(action);
stack.setValue("bar", "3x");
Map conversionErrors = (Map) stack.getContext().get(ActionContext.CONVERSION_ERRORS);
assertTrue(conversionErrors.containsKey("bar"));
}
public void testObjectSettingWithInvalidValueDoesNotCauseSetCalledWithNull() {
SimpleAction action = new SimpleAction();
action.setBean(new TestBean());
OgnlValueStack stack = createValueStack();
stack.getContext().put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE);
stack.push(action);
try {
stack.setValue("bean", "foobar", true);
fail("Should have thrown a type conversion exception");
} catch (XWorkException e) {
// expected
}
Map conversionErrors = (Map) stack.getContext().get(ActionContext.CONVERSION_ERRORS);
assertTrue(conversionErrors.containsKey("bean"));
assertNotNull(action.getBean());
}
public void testSerializable() throws IOException, ClassNotFoundException {
OgnlValueStack vs = createValueStack();
Dog dog = new Dog();
dog.setAge(12);
dog.setName("Rover");
vs.push(dog);
assertEquals("Rover", vs.findValue("name", String.class));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(vs);
oos.flush();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
OgnlValueStack newVs = (OgnlValueStack) ois.readObject();
assertEquals("Rover", newVs.findValue("name", String.class));
}
public void testSetAfterPush() {
OgnlValueStack vs = createValueStack();
Dog d = new Dog();
d.setName("Rover");
vs.push(d);
vs.set("name", "Bill");
assertEquals("Bill", vs.findValue("name"));
}
public void testSetBarAsString() {
Foo foo = new Foo();
OgnlValueStack vs = createValueStack();
vs.push(foo);
vs.setValue("bar", "bar:123");
assertEquals("bar", foo.getBar().getTitle());
assertEquals(123, foo.getBar().getSomethingElse());
}
public void testSetBeforePush() {
OgnlValueStack vs = createValueStack();
vs.set("name", "Bill");
Dog d = new Dog();
d.setName("Rover");
vs.push(d);
assertEquals("Rover", vs.findValue("name"));
}
public void testSetDeepBarAsString() {
Foo foo = new Foo();
Foo foo2 = new Foo();
foo.setChild(foo2);
OgnlValueStack vs = createValueStack();
vs.push(foo);
vs.setValue("child.bar", "bar:123");
assertEquals("bar", foo.getChild().getBar().getTitle());
assertEquals(123, foo.getChild().getBar().getSomethingElse());
}
public void testSetNullList() {
Foo foo = new Foo();
OgnlValueStack vs = createValueStack();
vs.getContext().put(ReflectionContextState.CREATE_NULL_OBJECTS, Boolean.TRUE);
vs.push(foo);
vs.setValue("cats[0].name", "Cat One");
vs.setValue("cats[1].name", "Cat Two");
assertNotNull(foo.getCats());
assertEquals(2, foo.getCats().size());
assertEquals("Cat One", ((Cat) foo.getCats().get(0)).getName());
assertEquals("Cat Two", ((Cat) foo.getCats().get(1)).getName());
vs.setValue("annotatedCats[0].name", "Cat One By Annotation");
vs.setValue("annotatedCats[1].name", "Cat Two By Annotation");
assertNotNull(foo.getAnnotatedCats());
assertEquals(2, foo.getAnnotatedCats().size());
assertEquals("Cat One By Annotation", ((Cat) foo.getAnnotatedCats().get(0)).getName());
assertEquals("Cat Two By Annotation", ((Cat) foo.getAnnotatedCats().get(1)).getName());
vs.setValue("cats[0].foo.cats[1].name", "Deep null cat");
assertNotNull(((Cat) foo.getCats().get(0)).getFoo());
assertNotNull(((Cat) foo.getCats().get(0)).getFoo().getCats());
assertNotNull(((Cat) foo.getCats().get(0)).getFoo().getCats().get(1));
assertEquals("Deep null cat", ((Cat) ((Cat) foo.getCats().get(0)).getFoo().getCats().get(1)).getName());
vs.setValue("annotatedCats[0].foo.annotatedCats[1].name", "Deep null cat by annotation");
assertNotNull(((Cat) foo.getAnnotatedCats().get(0)).getFoo());
assertNotNull(((Cat) foo.getAnnotatedCats().get(0)).getFoo().getAnnotatedCats());
assertNotNull(((Cat) foo.getAnnotatedCats().get(0)).getFoo().getAnnotatedCats().get(1));
assertEquals("Deep null cat by annotation", ((Cat) ((Cat) foo.getAnnotatedCats().get(0)).getFoo().getAnnotatedCats().get(1)).getName());
}
public void testSetMultiple() {
OgnlValueStack vs = createValueStack();
int origSize = vs.getRoot().size();
vs.set("something", new Object());
vs.set("somethingElse", new Object());
vs.set("yetSomethingElse", new Object());
assertEquals(origSize + 1, vs.getRoot().size());
}
public void testSetNullMap() {
Foo foo = new Foo();
OgnlValueStack vs = createValueStack();
vs.getContext().put(ReflectionContextState.CREATE_NULL_OBJECTS, Boolean.TRUE);
vs.push(foo);
vs.setValue("catMap['One'].name", "Cat One");
vs.setValue("catMap['Two'].name", "Cat Two");
assertNotNull(foo.getCatMap());
assertEquals(2, foo.getCatMap().size());
assertEquals("Cat One", ((Cat) foo.getCatMap().get("One")).getName());
assertEquals("Cat Two", ((Cat) foo.getCatMap().get("Two")).getName());
vs.setValue("catMap['One'].foo.catMap['Two'].name", "Deep null cat");
assertNotNull(((Cat) foo.getCatMap().get("One")).getFoo());
assertNotNull(((Cat) foo.getCatMap().get("One")).getFoo().getCatMap());
assertNotNull(((Cat) foo.getCatMap().get("One")).getFoo().getCatMap().get("Two"));
assertEquals("Deep null cat", ((Cat) ((Cat) foo.getCatMap().get("One")).getFoo().getCatMap().get("Two")).getName());
}
public void testSetReallyDeepBarAsString() {
Foo foo = new Foo();
Foo foo2 = new Foo();
foo.setChild(foo2);
Foo foo3 = new Foo();
foo2.setChild(foo3);
OgnlValueStack vs = createValueStack();
vs.push(foo);
vs.setValue("child.child.bar", "bar:123");
assertEquals("bar", foo.getChild().getChild().getBar().getTitle());
assertEquals(123, foo.getChild().getChild().getBar().getSomethingElse());
}
public void testSettingDogGender() {
OgnlValueStack vs = createValueStack();
Dog dog = new Dog();
vs.push(dog);
vs.setValue("male", "false");
assertEquals(false, dog.isMale());
}
public void testStatics() {
OgnlValueStack vs = createValueStack();
Cat cat = new Cat();
vs.push(cat);
Dog dog = new Dog();
dog.setAge(12);
dog.setName("Rover");
vs.push(dog);
assertEquals("Canine", vs.findValue("@vs@SCIENTIFIC_NAME"));
assertEquals("Canine", vs.findValue("@vs1@SCIENTIFIC_NAME"));
assertEquals("Feline", vs.findValue("@vs2@SCIENTIFIC_NAME"));
assertEquals(new Integer(BigDecimal.ROUND_HALF_DOWN), vs.findValue("@java.math.BigDecimal@ROUND_HALF_DOWN"));
assertNull(vs.findValue("@vs3@BLAH"));
assertNull(vs.findValue("@com.nothing.here.Nothing@BLAH"));
}
/**
* Fails on 2.5.20 and earlier - tested on 2.5 (5/5/2016) and failed
* @since 2.5.21
*/
public void testNotThrowExceptionOnTopMissingProperty() {
OgnlValueStack vs = createValueStack();
Dog dog = new Dog();
dog.setName("Rover");
vs.push(dog);
Cat cat = new Cat();
vs.push(cat);
vs.setValue("age", 12, true);
assertEquals(12, vs.findValue("age", true));
assertEquals(12, vs.findValue("age", Integer.class, true));
assertEquals(12, vs.findValue("getAge()", true));
assertEquals(12, vs.findValue("getAge()", Integer.class, true));
}
/**
* Fails on 2.5.20 and earlier - tested on 2.5 (5/5/2016) and failed
* @since 2.5.21
*/
public void testNotSkipUserReturnedNullValues() {
OgnlValueStack vs = createValueStack();
Dog dog = new Dog();
dog.setName("Rover");
vs.push(dog);
Cat cat = new Cat();
vs.push(cat);
// should not skip returned null values from cat.name
assertNull(vs.findValue("name", true));
assertNull(vs.findValue("name", String.class, true));
assertNull(vs.findValue("getName()", true));
assertNull(vs.findValue("getName()", String.class, true));
}
public void testTop() {
OgnlValueStack vs = createValueStack();
Dog dog1 = new Dog();
dog1.setAge(12);
dog1.setName("Rover");
Dog dog2 = new Dog();
dog2.setAge(1);
dog2.setName("Jack");
vs.push(dog1);
vs.push(dog2);
assertEquals(dog2, vs.findValue("top"));
assertEquals("Jack", vs.findValue("top.name"));
}
public void testTopIsDefaultTextProvider() {
OgnlValueStack vs = createValueStack();
assertEquals(container.getInstance(TextProvider.class, "system"), vs.findValue("top"));
}
public void testTwoDogs() {
OgnlValueStack vs = createValueStack();
Dog dog1 = new Dog();
dog1.setAge(12);
dog1.setName("Rover");
Dog dog2 = new Dog();
dog2.setAge(1);
dog2.setName("Jack");
vs.push(dog1);
vs.push(dog2);
assertEquals("Jack", vs.findValue("name"));
assertEquals("Rover", vs.findValue("[1].name"));
assertEquals(dog2, vs.pop());
assertEquals("Rover", vs.findValue("name"));
}
public void testTypeConversionError() {
TestBean bean = new TestBean();
OgnlValueStack stack = createValueStack();
stack.push(bean);
stack.getContext().put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE);
try {
stack.setValue("count", "a", true);
fail("Should have thrown a type conversion exception");
} catch (XWorkException e) {
// expected
}
Map conversionErrors = (Map) stack.getContext().get(ActionContext.CONVERSION_ERRORS);
assertTrue(conversionErrors.containsKey("count"));
}
public void testConstructorWithAStack() {
OgnlValueStack stack = createValueStack();
stack.push("Hello World");
OgnlValueStack stack2 = new OgnlValueStack(stack,
container.getInstance(XWorkConverter.class),
(CompoundRootAccessor) container.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()), true);
container.inject(stack2);
assertEquals(stack.getRoot(), stack2.getRoot());
assertEquals(stack.peek(), stack2.peek());
assertEquals("Hello World", stack2.pop());
}
public void testDefaultType() {
OgnlValueStack stack = createValueStack();
stack.setDefaultType(String.class);
stack.push("Hello World");
assertEquals("Hello World", stack.findValue("top"));
assertEquals(null, stack.findValue(null));
stack.setDefaultType(Integer.class);
stack.push(new Integer(123));
assertEquals(new Integer(123), stack.findValue("top"));
}
public void testFindString() {
OgnlValueStack stack = createValueStack();
stack.setDefaultType(Integer.class);
stack.push("Hello World");
assertEquals("Hello World", stack.findString("top"));
assertEquals(null, stack.findString(null));
}
public void testExpOverrides() {
Map overrides = new HashMap();
overrides.put("claus", "top");
OgnlValueStack stack = createValueStack();
stack.setExprOverrides(overrides);
stack.push("Hello World");
assertEquals("Hello World", stack.findValue("claus"));
assertEquals("Hello World", stack.findString("claus"));
assertEquals("Hello World", stack.findValue("top"));
assertEquals("Hello World", stack.findString("top"));
assertEquals("Hello World", stack.findValue("claus", String.class));
assertEquals("Hello World", stack.findValue("top", String.class));
stack.getContext().put("santa", "Hello Santa");
assertEquals("Hello Santa", stack.findValue("santa", String.class));
assertEquals(null, stack.findValue("unknown", String.class));
}
public void testWarnAboutInvalidProperties() {
OgnlValueStack stack = createValueStack();
MyAction action = new MyAction();
action.setName("Don");
stack.push(action);
// how to test the warning was logged?
assertEquals("Don", stack.findValue("name", String.class));
assertEquals(null, stack.findValue("address", String.class));
// should log warning
assertEquals(null, stack.findValue("address.invalidProperty", String.class));
// if country is null, OGNL throws an exception
/*action.setAddress(new Address());
stack.push(action);*/
// should log warning
assertEquals(null, stack.findValue("address.country.id", String.class));
assertEquals(null, stack.findValue("address.country.name", String.class));
}
/**
* Test a default OgnlValueStackFactory and OgnlValueStack generated by it
* when a default configuration is used.
*/
public void testOgnlValueStackFromOgnlValueStackFactoryDefaultConfig() {
OgnlValueStackFactory ognlValueStackFactory = getValueStackFactory();
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
Object accessedValue;
// An OgnlValueStackFactory using a container config with default (from XWorkConfigurationProvider)
// static method access flag value present should prevent staticMethodAccess but allow staticFieldAccess.
assertFalse("OgnlValueStackFactory staticMethodAccess (default flag) not false?", containerAllowsStaticMethodAccess(ognlValueStackFactory.container));
// An OgnlValueStack created from the above OgnlValueStackFactory should allow public field access,
// but prevent non-public field access. It should also deny static method access.
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
assertNull("able to access static method (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
assertEquals("accessed static final public field value not equal to actual?", accessedValue, STATIC_FINAL_PUBLIC_ATTRIBUTE);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
assertEquals("accessed static public field value not equal to actual?", accessedValue, STATIC_PUBLIC_ATTRIBUTE);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
assertNull("accessed final package field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
assertNull("accessed package field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
assertNull("accessed final protected field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
assertNull("accessed protected field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
assertNull("accessed final private field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
assertNull("accessed private field (result not null) ?", accessedValue);
}
/**
* Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
* when no static method access flag is set (not present in configuration).
*/
public void testOgnlValueStackFromOgnlValueStackFactoryNoFlagsSet() {
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(null);
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
Object accessedValue;
// An OgnlValueStackFactory using a container config with no static method access flag value present
// (such as from a DefaultConfiguration vs. XWorkConfigurationProvider) should
// prevent staticMethodAccess and allow staticFieldAccess.
// Note: Under normal circumstances, explicit static method access configuration flag should be present,
// but this specific check verifies what happens if that configuration flags is not present.
assertFalse("OgnlValueStackFactory staticMethodAccess (no flag present) not false?", containerAllowsStaticMethodAccess(ognlValueStackFactory.container));
// An OgnlValueStack created from the above OgnlValueStackFactory should allow public field access,
// and prevent non-public field access. It should also deny static method access.
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
assertNull("able to access static method (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
assertEquals("accessed static final public field value not equal to actual?", accessedValue, STATIC_FINAL_PUBLIC_ATTRIBUTE);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
assertEquals("accessed static public field value not equal to actual?", accessedValue, STATIC_PUBLIC_ATTRIBUTE);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
assertNull("accessed final package field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
assertNull("accessed package field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
assertNull("accessed final protected field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
assertNull("accessed protected field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
assertNull("accessed final private field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
assertNull("accessed private field (result not null) ?", accessedValue);
}
/**
* Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
* when static method access flag is set to false.
*/
public void testOgnlValueStackFromOgnlValueStackFactoryNoStaticMethodAccess() {
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(false);
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
Object accessedValue;
// An OgnlValueStackFactory using a container config with static method access flag set false should
// prevent staticMethodAccess and allow staticFieldAccess.
assertFalse("OgnlValueStackFactory staticMethodAccess (set false) not false?", containerAllowsStaticMethodAccess(ognlValueStackFactory.container));
// An OgnlValueStack created from the above OgnlValueStackFactory should allow public field access,
// and prevent non-public field access. It should also deny static method access.
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
assertNull("able to access static method (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
assertEquals("accessed static final public field value not equal to actual?", accessedValue, STATIC_FINAL_PUBLIC_ATTRIBUTE);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
assertEquals("accessed static public field value not equal to actual?", accessedValue, STATIC_PUBLIC_ATTRIBUTE);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
assertNull("accessed final package field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
assertNull("accessed package field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
assertNull("accessed final protected field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
assertNull("accessed protected field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
assertNull("accessed final private field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
assertNull("accessed private field (result not null) ?", accessedValue);
}
/**
* Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
* when static method access flag set to true.
*/
public void testOgnlValueStackFromOgnlValueStackFactoryStaticMethodAccess() {
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(true);
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
Object accessedValue;
// An OgnlValueStackFactory using a container config with static method access flag set true should
// allow both staticMethodAccess and staticFieldAccess.
assertTrue("OgnlValueStackFactory staticMethodAccess (set true) not true?", containerAllowsStaticMethodAccess(ognlValueStackFactory.container));
// An OgnlValueStack created from the above OgnlValueStackFactory should allow public field access,
// but prevent non-public field access. It should also allow static method access.
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
assertNotNull("unable to access static method (result null) ?", accessedValue);
assertEquals("accessed static method result not equal to expected?", accessedValue, staticInteger100Method());
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
assertEquals("accessed static final public field value not equal to actual?", accessedValue, STATIC_FINAL_PUBLIC_ATTRIBUTE);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
assertEquals("accessed static public field value not equal to actual?", accessedValue, STATIC_PUBLIC_ATTRIBUTE);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
assertNull("accessed final package field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
assertNull("accessed package field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
assertNull("accessed final protected field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
assertNull("accessed protected field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
assertNull("accessed final private field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
assertNull("accessed private field (result not null) ?", accessedValue);
}
protected boolean containerAllowsStaticMethodAccess(Container checkContainer) {
return Boolean.parseBoolean(checkContainer.getInstance(String.class, XWorkConstants.ALLOW_STATIC_METHOD_ACCESS));
}
private void reloadTestContainerConfiguration(final Boolean allowStaticMethod) throws Exception {
loadConfigurationProviders(new StubConfigurationProvider() {
@Override
public void register(ContainerBuilder builder,
LocatableProperties props) throws ConfigurationException {
// null values simulate undefined (by removing).
// undefined values then should be evaluated to false
if (props.containsKey(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS)) {
props.remove(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS);
}
if (props.containsKey(XWorkConstants.ALLOW_STATIC_METHOD_ACCESS)) {
props.remove(XWorkConstants.ALLOW_STATIC_METHOD_ACCESS);
}
if (allowStaticMethod != null) {
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, "" + allowStaticMethod);
props.setProperty(XWorkConstants.ALLOW_STATIC_METHOD_ACCESS, "" + allowStaticMethod);
}
}
});
ognlUtil = container.getInstance(OgnlUtil.class);
}
class BadJavaBean {
private int count;
private int count2;
public void setCount(int count) {
this.count = count;
}
public String getCount() {
return "" + count;
}
public void setCount2(String count2) {
this.count2 = Integer.parseInt(count2);
}
public int getCount2() {
return count2;
}
}
class MyAction {
private Long id;
private String name;
private Address address;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
class Address {
private String address;
private Country country;
private String city;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public Country getCountry() {
return country;
}
public void setCountry(Country country) {
this.country = country;
}
}
class Country {
private String iso;
private String name;
private String displayName;
public String getIso() {
return iso;
}
public void setIso(String iso) {
this.iso = iso;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
}
class TestAppender extends AbstractAppender {
List<LogEvent> logEvents = new ArrayList<>();
TestAppender() {
super("TestAppender", null, null, false, null);
}
@Override
public void append(LogEvent logEvent) {
logEvents.add(logEvent);
}
}
}
enum MyNumbers {
ONE, TWO, THREE
}