001    /*
002     * $Id: TestOgnlRuntime.java 1203594 2011-11-18 11:04:51Z mcucchiara $
003     * Licensed to the Apache Software Foundation (ASF) under one
004     * or more contributor license agreements.  See the NOTICE file
005     * distributed with this work for additional information
006     * regarding copyright ownership.  The ASF licenses this file
007     * to you under the Apache License, Version 2.0 (the
008     * "License"); you may not use this file except in compliance
009     * with the License.  You may obtain a copy of the License at
010     *
011     * http://www.apache.org/licenses/LICENSE-2.0
012     *
013     * Unless required by applicable law or agreed to in writing,
014     * software distributed under the License is distributed on an
015     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016     * KIND, either express or implied.  See the License for the
017     * specific language governing permissions and limitations
018     * under the License.
019     */
020    package org.apache.commons.ognl;
021    
022    import org.apache.commons.ognl.enhance.OgnlExpressionCompiler;
023    import org.apache.commons.ognl.internal.CacheException;
024    import org.apache.commons.ognl.test.objects.BaseGeneric;
025    import org.apache.commons.ognl.test.objects.Bean1;
026    import org.apache.commons.ognl.test.objects.Bean2;
027    import org.apache.commons.ognl.test.objects.FormImpl;
028    import org.apache.commons.ognl.test.objects.GameGeneric;
029    import org.apache.commons.ognl.test.objects.GameGenericObject;
030    import org.apache.commons.ognl.test.objects.GenericCracker;
031    import org.apache.commons.ognl.test.objects.GenericService;
032    import org.apache.commons.ognl.test.objects.GenericServiceImpl;
033    import org.apache.commons.ognl.test.objects.GetterMethods;
034    import org.apache.commons.ognl.test.objects.IComponent;
035    import org.apache.commons.ognl.test.objects.IForm;
036    import org.apache.commons.ognl.test.objects.ListSource;
037    import org.apache.commons.ognl.test.objects.ListSourceImpl;
038    import org.apache.commons.ognl.test.objects.OtherObjectIndexed;
039    import org.apache.commons.ognl.test.objects.Root;
040    import org.apache.commons.ognl.test.objects.SetterReturns;
041    import org.apache.commons.ognl.test.objects.SubclassSyntheticObject;
042    import org.junit.Test;
043    
044    import java.beans.IntrospectionException;
045    import java.beans.PropertyDescriptor;
046    import java.io.Serializable;
047    import java.lang.reflect.Field;
048    import java.lang.reflect.Method;
049    import java.util.Arrays;
050    import java.util.List;
051    
052    import static junit.framework.Assert.*;
053    
054    /**
055     * Tests various methods / functionality of {@link org.apache.commons.ognl.OgnlRuntime}.
056     */
057    public class TestOgnlRuntime
058    {
059    
060        @Test
061        public void test_Get_Super_Or_Interface_Class()
062            throws Exception
063        {
064            ListSource list = new ListSourceImpl();
065    
066            Method method = OgnlRuntime.getReadMethod( list.getClass(), "total" );
067            assertNotNull( method );
068    
069            OgnlContext context = (OgnlContext) Ognl.createDefaultContext( null );
070            assertEquals( ListSource.class,
071                          OgnlRuntime.getCompiler( context ).getSuperOrInterfaceClass( method, list.getClass() ) );
072        }
073    
074        @Test
075        public void test_Get_Private_Class()
076            throws Exception
077        {
078            List list = Arrays.asList( "hello", "world" );
079    
080            Method m = OgnlRuntime.getReadMethod( list.getClass(), "iterator" );
081            assertNotNull( m );
082    
083            OgnlContext context = (OgnlContext) Ognl.createDefaultContext( null );
084            assertEquals( Iterable.class,
085                          OgnlRuntime.getCompiler( context ).getSuperOrInterfaceClass( m, list.getClass() ) );
086        }
087    
088        @Test
089        public void test_Complicated_Inheritance()
090            throws Exception
091        {
092            IForm form = new FormImpl();
093    
094            Method method = OgnlRuntime.getWriteMethod( form.getClass(), "clientId" );
095            assertNotNull( method );
096    
097            OgnlContext context = (OgnlContext) Ognl.createDefaultContext( null );
098            assertEquals( IComponent.class,
099                          OgnlRuntime.getCompiler( context ).getSuperOrInterfaceClass( method, form.getClass() ) );
100        }
101    
102        @Test
103        public void test_Get_Read_Method()
104            throws Exception
105        {
106            Method method = OgnlRuntime.getReadMethod( Bean2.class, "pageBreakAfter" );
107            assertNotNull( method );
108    
109            assertEquals( "isPageBreakAfter", method.getName() );
110        }
111    
112        class TestGetters
113        {
114            public boolean isEditorDisabled()
115            {
116                return false;
117            }
118    
119            public boolean isDisabled()
120            {
121                return true;
122            }
123    
124            public boolean isNotAvailable()
125            {
126                return false;
127            }
128    
129            public boolean isAvailable()
130            {
131                return true;
132            }
133        }
134    
135        @Test
136        public void test_Get_Read_Method_Multiple()
137            throws Exception
138        {
139            Method method = OgnlRuntime.getReadMethod( TestGetters.class, "disabled" );
140            assertNotNull( method );
141    
142            assertEquals( "isDisabled", method.getName() );
143        }
144    
145        @Test
146        public void test_Get_Read_Method_Multiple_Boolean_Getters()
147            throws Exception
148        {
149            Method method = OgnlRuntime.getReadMethod( TestGetters.class, "available" );
150            assertNotNull( method );
151    
152            assertEquals( "isAvailable", method.getName() );
153    
154            method = OgnlRuntime.getReadMethod( TestGetters.class, "notAvailable" );
155            assertNotNull( method );
156    
157            assertEquals( "isNotAvailable", method.getName() );
158        }
159    
160        @Test
161        public void test_Find_Method_Mixed_Boolean_Getters()
162            throws Exception
163        {
164            Method method = OgnlRuntime.getReadMethod( GetterMethods.class, "allowDisplay" );
165            assertNotNull( method );
166    
167            assertEquals( "getAllowDisplay", method.getName() );
168        }
169    
170        @Test
171        public void test_Get_Appropriate_Method()
172            throws Exception
173        {
174            ListSource list = new ListSourceImpl();
175            OgnlContext context = (OgnlContext) Ognl.createDefaultContext( null );
176    
177            Object ret = OgnlRuntime.callMethod( context, list, "addValue", new String[]{ null } );
178    
179            assert ret != null;
180        }
181    
182        @Test
183        public void test_Call_Static_Method_Invalid_Class()
184        {
185    
186            try
187            {
188                OgnlContext context = (OgnlContext) Ognl.createDefaultContext( null );
189                OgnlRuntime.callStaticMethod( context, "made.up.Name", "foo", null );
190    
191                fail( "ClassNotFoundException should have been thrown by previous reference to <made.up.Name> class." );
192            }
193            catch ( Exception et )
194            {
195                assertTrue( MethodFailedException.class.isInstance( et ) );
196                assertTrue( et.getMessage().contains( "made.up.Name" ) );
197            }
198        }
199    
200        @Test
201        public void test_Setter_Returns()
202            throws Exception
203        {
204            OgnlContext context = (OgnlContext) Ognl.createDefaultContext( null );
205            SetterReturns root = new SetterReturns();
206    
207            Method m = OgnlRuntime.getWriteMethod( root.getClass(), "value" );
208            assertTrue( m != null );
209    
210            Ognl.setValue( "value", context, root, "12__" );
211            assertEquals( Ognl.getValue( "value", context, root ), "12__" );
212        }
213    
214        @Test
215        public void test_Call_Method_VarArgs()
216            throws Exception
217        {
218            OgnlContext context = (OgnlContext) Ognl.createDefaultContext( null );
219            GenericService service = new GenericServiceImpl();
220    
221            GameGenericObject argument = new GameGenericObject();
222    
223            Object[] args = OgnlRuntime.getObjectArrayPool().create( 2 );
224            args[0] = argument;
225    
226            assertEquals( "Halo 3", OgnlRuntime.callMethod( context, service, "getFullMessageFor", args ) );
227        }
228    
229        @Test
230        public void test_Class_Cache_Inspector()
231            throws Exception
232        {
233            OgnlRuntime.cache.clear();
234    
235            assertEquals( 0, OgnlRuntime.cache.propertyDescriptorCache.getSize() );
236    
237            Root root = new Root();
238            OgnlContext context = (OgnlContext) Ognl.createDefaultContext( null );
239            Node expr = Ognl.compileExpression( context, root, "property.bean3.value != null" );
240    
241            assertTrue( (Boolean) expr.getAccessor().get( context, root ) );
242    
243            int size = OgnlRuntime.cache.propertyDescriptorCache.getSize();
244            assertTrue( size > 0 );
245    
246            OgnlRuntime.clearCache();
247            assertEquals( 0, OgnlRuntime.cache.propertyDescriptorCache.getSize() );
248    
249            // now register class cache prevention
250    
251            OgnlRuntime.setClassCacheInspector( new TestCacheInspector() );
252    
253            expr = Ognl.compileExpression( context, root, "property.bean3.value != null" );
254            assertTrue( (Boolean) expr.getAccessor().get( context, root ) );
255    
256            assertEquals( ( size - 1 ), OgnlRuntime.cache.propertyDescriptorCache.getSize() );
257        }
258    
259        class TestCacheInspector
260            implements ClassCacheInspector
261        {
262    
263            public boolean shouldCache( Class<?> type )
264            {
265                return !( type == null || type == Root.class );
266            }
267        }
268    
269        @Test
270        public void test_Set_Generic_Parameter_Types()
271            throws Exception
272        {
273            OgnlContext context = (OgnlContext) Ognl.createDefaultContext( null );
274    
275            Method method = OgnlRuntime.getSetMethod( context, GenericCracker.class, "param" );
276            assertNotNull( method );
277    
278            Class[] types = method.getParameterTypes();
279            assertEquals( 1, types.length );
280            assertEquals( Integer.class, types[0] );
281        }
282    
283        @Test
284        public void test_Get_Generic_Parameter_Types()
285            throws Exception
286        {
287            OgnlContext context = (OgnlContext) Ognl.createDefaultContext( null );
288    
289            Method method = OgnlRuntime.getGetMethod( context, GenericCracker.class, "param" );
290            assertNotNull( method );
291    
292            assertEquals( Integer.class, method.getReturnType() );
293        }
294    
295        @Test
296        public void test_Find_Parameter_Types()
297            throws Exception
298        {
299            OgnlContext context = (OgnlContext) Ognl.createDefaultContext( null );
300    
301            Method method = OgnlRuntime.getSetMethod( context, GameGeneric.class, "ids" );
302            assertNotNull( method );
303    
304            Class[] types = OgnlRuntime.findParameterTypes( GameGeneric.class, method );
305            assertEquals( 1, types.length );
306            assertEquals( Long[].class, types[0] );
307        }
308    
309        @Test
310        public void test_Find_Parameter_Types_Superclass()
311            throws Exception
312        {
313            OgnlContext context = (OgnlContext) Ognl.createDefaultContext( null );
314    
315            Method method = OgnlRuntime.getSetMethod( context, BaseGeneric.class, "ids" );
316            assertNotNull( method );
317    
318            Class[] types = OgnlRuntime.findParameterTypes( BaseGeneric.class, method );
319            assertEquals( 1, types.length );
320            assertEquals( Serializable[].class, types[0] );
321        }
322    
323        @Test
324        public void test_Get_Declared_Methods_With_Synthetic_Methods()
325            throws Exception
326        {
327            List result = OgnlRuntime.getDeclaredMethods( SubclassSyntheticObject.class, "list", false );
328    
329            // synthetic method would be
330            // "public volatile java.util.List org.ognl.test.objects.SubclassSyntheticObject.getList()",
331            // causing method return size to be 3
332    
333            assertEquals( 2, result.size() );
334        }
335    
336        @Test
337        public void test_Get_Property_Descriptors_With_Synthetic_Methods()
338            throws Exception
339        {
340            PropertyDescriptor propertyDescriptor = OgnlRuntime.getPropertyDescriptor( SubclassSyntheticObject.class, "list" );
341    
342            assert propertyDescriptor != null;
343            assert OgnlRuntime.isMethodCallable( propertyDescriptor.getReadMethod() );
344        }
345    
346        private static class GenericParent<T>
347        {
348            public void save( T entity )
349            {
350    
351            }
352        }
353    
354        private static class StringChild
355            extends GenericParent<String>
356        {
357    
358        }
359    
360        private static class LongChild
361            extends GenericParent<Long>
362        {
363    
364        }
365    
366        /**
367         * Tests OGNL parameter discovery.
368         */
369        @Test
370        public void testOGNLParameterDiscovery()
371            throws NoSuchMethodException, CacheException
372        {
373            Method saveMethod = GenericParent.class.getMethod( "save", Object.class );
374            System.out.println( saveMethod );
375    
376            Class[] longClass = OgnlRuntime.findParameterTypes( LongChild.class, saveMethod );
377            assertNotSame( longClass[0], String.class );
378            assertSame( longClass[0], Long.class );
379    
380            Class[] stringClass = OgnlRuntime.findParameterTypes( StringChild.class, saveMethod );
381            assertNotSame( "The cached parameter types from previous calls are used", stringClass[0], Long.class );
382            assertSame( stringClass[0], String.class );
383        }
384    
385        @Test
386        public void testGetField()
387            throws OgnlException
388        {
389            Field field = OgnlRuntime.getField( OtherObjectIndexed.class, "attributes" );
390            assertNotNull( "Field is null", field );
391        }
392    
393        @Test
394        public void testGetSetMethod()
395            throws IntrospectionException, OgnlException
396        {
397            Method setter = OgnlRuntime.getSetMethod( null, Bean1.class, "bean2" );
398            Method getter = OgnlRuntime.getGetMethod( null, Bean1.class, "bean2" );
399            assertNotNull( getter );
400            assertNull( setter );
401        }
402    
403        @Test
404        public void testGetCompiler()
405        {
406            OgnlContext context = (OgnlContext) Ognl.createDefaultContext( null );
407            OgnlExpressionCompiler compiler1 = OgnlRuntime.getCompiler( context );
408            context.put( "root2", new Root() );
409            OgnlExpressionCompiler compiler2 = OgnlRuntime.getCompiler( context );
410            assertSame( "compilers are not the same", compiler1, compiler2 );
411        }
412    
413        @Test
414        public void testGetPropertyDescriptorFromArray()
415            throws Exception
416        {
417            PropertyDescriptor propertyDescriptor =
418                OgnlRuntime.getPropertyDescriptorFromArray( Root.class, "disabled" );
419            assertEquals( "disabled", propertyDescriptor.getName() );
420        }
421    }