| /* |
| * 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 |
| } |