/* * Copyright 2009 Martin Grotzke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package de.javakaffee.web.msm.serializer.javolution; import static de.javakaffee.web.msm.serializer.javolution.TestClasses.createPerson; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.Currency; import java.util.Date; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import javolution.xml.XMLObjectReader; import javolution.xml.XMLObjectWriter; import javolution.xml.XMLReferenceResolver; import javolution.xml.stream.XMLStreamException; import org.apache.catalina.core.StandardContext; import org.apache.catalina.loader.WebappLoader; import org.apache.catalina.session.StandardSession; import org.apache.commons.lang.mutable.MutableInt; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import de.javakaffee.web.msm.MemcachedBackupSession; import de.javakaffee.web.msm.MemcachedBackupSessionManager; import de.javakaffee.web.msm.serializer.javolution.TestClasses.Container; import de.javakaffee.web.msm.serializer.javolution.TestClasses.CounterHolder; import de.javakaffee.web.msm.serializer.javolution.TestClasses.CounterHolderArray; import de.javakaffee.web.msm.serializer.javolution.TestClasses.Email; import de.javakaffee.web.msm.serializer.javolution.TestClasses.HashMapWithIntConstructorOnly; import de.javakaffee.web.msm.serializer.javolution.TestClasses.Holder; import de.javakaffee.web.msm.serializer.javolution.TestClasses.HolderArray; import de.javakaffee.web.msm.serializer.javolution.TestClasses.HolderList; import de.javakaffee.web.msm.serializer.javolution.TestClasses.MyContainer; import de.javakaffee.web.msm.serializer.javolution.TestClasses.MyXMLSerializable; import de.javakaffee.web.msm.serializer.javolution.TestClasses.Person; import de.javakaffee.web.msm.serializer.javolution.TestClasses.Person.Gender; import de.javakaffee.web.msm.serializer.javolution.TestClasses.SomeInterface; /** * Test for {@link JavolutionTranscoder} * * @author <a href="mailto:martin.grotzke@javakaffee.de">Martin Grotzke</a> */ public class JavolutionTranscoderTest { private MemcachedBackupSessionManager _manager; private JavolutionTranscoder _transcoder; @BeforeClass public void beforeTest() { _manager = new MemcachedBackupSessionManager(); final StandardContext container = new StandardContext(); _manager.setContainer( container ); final WebappLoader webappLoader = mock( WebappLoader.class ); when( webappLoader.getClassLoader() ).thenReturn( Thread.currentThread().getContextClassLoader() ); Assert.assertNotNull( webappLoader.getClassLoader(), "Webapp Classloader is null." ); _manager.getContainer().setLoader( webappLoader ); Assert.assertNotNull( _manager.getContainer().getLoader().getClassLoader(), "Classloader is null." ); _transcoder = new JavolutionTranscoder( _manager, true ); } @Test( enabled = true ) public void testStringBufferAndStringBuilderFormat() throws Exception { final MemcachedBackupSession session = _manager.createEmptySession(); session.setValid( true ); session.setAttribute( "stringbuffer", new StringBuffer( "<string\n&buffer/>" ) ); session.setAttribute( "stringbuilder", new StringBuilder( "<string\n&buffer/>" ) ); System.out.println( new String( _transcoder.serializeAttributes( session, session.getAttributesInternal() ) )); final Map<String, Object> deserialized = _transcoder.deserializeAttributes( _transcoder.serializeAttributes( session, session.getAttributesInternal() ) ); assertDeepEquals( deserialized, session.getAttributesInternal() ); } /** * This is test for issue #55: * Wicket's MiniMap cannot be deserialized with javolution serializer * * See http://code.google.com/p/memcached-session-manager/issues/detail?id=55 * * @throws Exception */ @Test( enabled = true ) public void testMapWithIntConstructorOnly() throws Exception { final MemcachedBackupSession session = _manager.createEmptySession(); session.setValid( true ); final HashMapWithIntConstructorOnly map = new HashMapWithIntConstructorOnly( 5 ); session.setAttribute( "map", map ); System.out.println( new String( _transcoder.serializeAttributes( session, session.getAttributesInternal() ) )); final Map<String, Object> deserialized = _transcoder.deserializeAttributes( _transcoder.serializeAttributes( session, session.getAttributesInternal() ) ); assertDeepEquals( deserialized, session.getAttributesInternal() ); assertDeepEquals( deserialized.get( "map" ), map ); } /** * This is test for issue #34: * msm-javolution-serializer: java.util.Currency gets deserialized with ReflectionFormat * * See http://code.google.com/p/memcached-session-manager/issues/detail?id=34 * * @throws Exception */ @Test( enabled = true ) public void testCurrency() throws Exception { final MemcachedBackupSession session = _manager.createEmptySession(); session.setValid( true ); final Currency orig = Currency.getInstance( "EUR" ); session.setAttribute( "currency1", orig ); session.setAttribute( "currency2", orig ); final Map<String, Object> deserialized = _transcoder.deserializeAttributes( _transcoder.serializeAttributes( session, session.getAttributesInternal() ) ); assertDeepEquals( deserialized, session.getAttributesInternal() ); // Check that the transient field defaultFractionDigits is initialized correctly (that was the bug) final Currency currency1 = (Currency) deserialized.get( "currency1" ); Assert.assertEquals( currency1.getCurrencyCode(), orig.getCurrencyCode() ); Assert.assertEquals( currency1.getDefaultFractionDigits(), orig.getDefaultFractionDigits() ); } /** * This is test for issue #33: * msm-javolution-serializer: ReflectionBinding does not honor XMLSerializable interface * * See http://code.google.com/p/memcached-session-manager/issues/detail?id=33 * * @throws Exception */ @Test( enabled = true ) public void testXMLSerializableSupport() throws Exception { final MemcachedBackupSession session = _manager.createEmptySession(); session.setValid( true ); final String attributeName = "myxmlserializable"; session.setAttribute( attributeName, new MyXMLSerializable( Runtime.getRuntime() ) ); final Map<String, Object> deserialized = _transcoder.deserializeAttributes( _transcoder.serializeAttributes( session, session.getAttributesInternal() ) ); assertDeepEquals( deserialized, session.getAttributesInternal() ); final MyXMLSerializable myXMLSerializable = (MyXMLSerializable) deserialized.get( attributeName ); Assert.assertNotNull( myXMLSerializable.getRuntime(), "Transient field runtime should be initialized by XMLFormat" + " used due to implementation of XMLSerializable." ); } /** * This is test for issue #30: * msm-javolution-serializer should support serialization of java.util.Collections$UnmodifiableMap * * See http://code.google.com/p/memcached-session-manager/issues/detail?id=30 * * @throws Exception */ @Test( enabled = true ) public void testJavaUtilCollectionsUnmodifiable() throws Exception { final MemcachedBackupSession session = _manager.createEmptySession(); session.setValid( true ); session.setAttribute( "unmodifiableList", Collections.unmodifiableList( new ArrayList<String>( Arrays.asList( "foo", "bar" ) ) ) ); final HashMap<String, String> m = new HashMap<String, String>(); m.put( "foo", "bar" ); session.setAttribute( "unmodifiableList", Collections.unmodifiableMap( m ) ); final Map<String, Object> deserialized = _transcoder.deserializeAttributes( _transcoder.serializeAttributes( session, session.getAttributesInternal() ) ); assertDeepEquals( deserialized, session.getAttributesInternal() ); } /** * This is the test for issue #28: * msm-javolution-serializer should support serialization of java.util.Collections$EmptyList * * See http://code.google.com/p/memcached-session-manager/issues/detail?id=28 * * @throws Exception */ @Test( enabled = true ) public void testJavaUtilLists() throws Exception { final MemcachedBackupSession session = _manager.createEmptySession(); session.setValid( true ); session.setAttribute( "emptyList", Collections.<String>emptyList() ); session.setAttribute( "arrayList", new ArrayList<String>() ); session.setAttribute( "arraysAsList", Arrays.asList( "foo", "bar" ) ); final Map<String, Object> deserialized = _transcoder.deserializeAttributes( _transcoder.serializeAttributes( session, session.getAttributesInternal() ) ); assertDeepEquals( deserialized, session.getAttributesInternal() ); } /** * This is another test for issue #28, just for maps: * msm-javolution-serializer should support serialization of java.util.Collections$EmptyList * * See http://code.google.com/p/memcached-session-manager/issues/detail?id=28 * * @throws Exception */ @Test( enabled = true ) public void testJavaUtilCollectionsEmptyMap() throws Exception { final MemcachedBackupSession session = _manager.createEmptySession(); session.setValid( true ); session.setAttribute( "emptyMap", Collections.<String, String>emptyMap() ); session.setAttribute( "hashMap", new HashMap<String, String>() ); final Map<String, Object> deserialized = _transcoder.deserializeAttributes( _transcoder.serializeAttributes( session, session.getAttributesInternal() ) ); assertDeepEquals( deserialized, session.getAttributesInternal() ); } @Test( enabled = true ) public void testProxy() throws Exception { final SomeInterface bean = TestClasses.createProxy(); final byte[] bytes = serialize( bean ); assertDeepEquals( deserialize( bytes ), bean ); } @Test( enabled = true ) public void testInnerClass() throws Exception { final Container container = TestClasses.createContainer( "some content" ); assertDeepEquals( deserialize( serialize( container ) ), container ); } @DataProvider( name = "sharedObjectIdentityProvider" ) protected Object[][] createSharedObjectIdentityProviderData() { return new Object[][] { { AtomicInteger.class.getSimpleName(), new AtomicInteger( 42 ) }, { Email.class.getSimpleName(), new Email( "foo bar", "foo.bar@example.com" ) } }; } @Test( enabled = true ) public <T> void testSharedObjectIdentity_CounterHolder() throws Exception { final AtomicInteger sharedObject = new AtomicInteger( 42 ); final CounterHolder holder1 = new CounterHolder( sharedObject ); final CounterHolder holder2 = new CounterHolder( sharedObject ); final CounterHolderArray holderHolder = new CounterHolderArray( holder1, holder2 ); final MemcachedBackupSession session = _manager.createEmptySession(); session.setValid( true ); session.setAttribute( "hh", holderHolder ); final Map<String, Object> deserialized = _transcoder.deserializeAttributes( _transcoder.serializeAttributes( session, session.getAttributesInternal() ) ); assertDeepEquals( deserialized, session.getAttributesInternal() ); final CounterHolderArray hhd = (CounterHolderArray) deserialized.get( "hh" ); Assert.assertTrue( hhd.holders[0].item == hhd.holders[1].item ); } @Test( enabled = true, dataProvider = "sharedObjectIdentityProvider" ) public <T> void testSharedObjectIdentityWithArray( final String name, final T sharedObject ) throws Exception { final Holder<T> holder1 = new Holder<T>( sharedObject ); final Holder<T> holder2 = new Holder<T>( sharedObject ); @SuppressWarnings( "unchecked" ) final HolderArray<T> holderHolder = new HolderArray<T>( holder1, holder2 ); final MemcachedBackupSession session = _manager.createEmptySession(); session.setValid( true ); session.setAttribute( name, holderHolder ); final Map<String, Object> deserialized = _transcoder.deserializeAttributes( _transcoder.serializeAttributes( session, session.getAttributesInternal() ) ); assertDeepEquals( deserialized, session.getAttributesInternal() ); @SuppressWarnings( "unchecked" ) final HolderArray<T> hhd = (HolderArray<T>) deserialized.get( name ); Assert.assertTrue( hhd.holders[0].item == hhd.holders[1].item ); } @Test( enabled = true, dataProvider = "sharedObjectIdentityProvider" ) public <T> void testSharedObjectIdentity( final String name, final T sharedObject ) throws Exception { final Holder<T> holder1 = new Holder<T>( sharedObject ); final Holder<T> holder2 = new Holder<T>( sharedObject ); @SuppressWarnings( "unchecked" ) final HolderList<T> holderHolder = new HolderList<T>( new ArrayList<Holder<T>>( Arrays.asList( holder1, holder2 ) ) ); final MemcachedBackupSession session = _manager.createEmptySession(); session.setValid( true ); session.setAttribute( name, holderHolder ); final Map<String, Object> deserialized = _transcoder.deserializeAttributes( _transcoder.serializeAttributes( session, session.getAttributesInternal() ) ); assertDeepEquals( deserialized, session.getAttributesInternal() ); @SuppressWarnings( "unchecked" ) final HolderList<T> hhd = (HolderList<T>) deserialized.get( name ); Assert.assertTrue( hhd.holders.get( 0 ).item == hhd.holders.get( 1 ).item ); } @DataProvider( name = "typesAsSessionAttributesProvider" ) protected Object[][] createTypesAsSessionAttributesData() { return new Object[][] { { int.class, 42 }, { long.class, 42 }, { Boolean.class, Boolean.TRUE }, { String.class, "42" }, { StringBuilder.class, new StringBuilder( "42" ) }, { StringBuffer.class, new StringBuffer( "42" ) }, { Class.class, String.class }, { Long.class, Long.valueOf( 42 ) }, { Integer.class, Integer.valueOf( 42 ) }, { Character.class, Character.valueOf( 'c' ) }, { Byte.class, Byte.valueOf( "b".getBytes()[0] ) }, { Double.class, Double.valueOf( 42d ) }, { Float.class, Float.valueOf( 42f ) }, { Short.class, Short.valueOf( (short) 42 ) }, { BigDecimal.class, new BigDecimal( 42 ) }, { AtomicInteger.class, new AtomicInteger( 42 ) }, { AtomicLong.class, new AtomicLong( 42 ) }, { MutableInt.class, new MutableInt( 42 ) }, { Integer[].class, new Integer[] { 42 } }, { Date.class, new Date( System.currentTimeMillis() - 10000 ) }, { Calendar.class, Calendar.getInstance() }, { Currency.class, Currency.getInstance( "EUR" ) }, { ArrayList.class, new ArrayList<String>( Arrays.asList( "foo" ) ) }, { int[].class, new int[] { 1, 2 } }, { long[].class, new long[] { 1, 2 } }, { short[].class, new short[] { 1, 2 } }, { float[].class, new float[] { 1, 2 } }, { double[].class, new double[] { 1, 2 } }, { int[].class, new int[] { 1, 2 } }, { byte[].class, "42".getBytes() }, { char[].class, "42".toCharArray() }, { String[].class, new String[] { "23", "42" } }, { Person[].class, new Person[] { createPerson( "foo bar", Gender.MALE, 42 ) } } }; } @Test( enabled = true, dataProvider = "typesAsSessionAttributesProvider" ) public <T> void testTypesAsSessionAttributes( final Class<T> type, final T instance ) throws Exception { final MemcachedBackupSession session = _manager.createEmptySession(); session.setValid( true ); session.setAttribute( type.getSimpleName(), instance ); final byte[] bytes = _transcoder.serializeAttributes( session, session.getAttributesInternal() ); assertDeepEquals( _transcoder.deserializeAttributes( bytes ), session.getAttributesInternal()); } @Test( enabled = true ) public void testTypesInContainerClass() throws Exception { final MemcachedBackupSession session = _manager.createEmptySession(); session.setValid( true ); session.setAttribute( MyContainer.class.getSimpleName(), new MyContainer() ); final Map<String, Object> deserialized = _transcoder.deserializeAttributes( _transcoder.serializeAttributes( session, session.getAttributesInternal() ) ); assertDeepEquals( deserialized, session.getAttributesInternal() ); } @Test( enabled = true ) public void testClassWithoutDefaultConstructor() throws Exception { final MemcachedBackupSession session = _manager.createEmptySession(); session.setValid( true ); session.setAttribute( "no-default constructor", TestClasses.createClassWithoutDefaultConstructor( "foo" ) ); final Map<String, Object> deserialized = _transcoder.deserializeAttributes( _transcoder.serializeAttributes( session, session.getAttributesInternal() ) ); assertDeepEquals( deserialized, session.getAttributesInternal() ); } @Test( enabled = true ) public void testPrivateClass() throws Exception { final MemcachedBackupSession session = _manager.createEmptySession(); session.setValid( true ); session.setAttribute( "pc", TestClasses.createPrivateClass( "foo" ) ); final Map<String, Object> deserialized = _transcoder.deserializeAttributes( _transcoder.serializeAttributes( session, session.getAttributesInternal() ) ); assertDeepEquals( deserialized, session.getAttributesInternal() ); } @Test( enabled = true ) public void testCollections() throws Exception { final MemcachedBackupSession session = _manager.createEmptySession(); session.setValid( true ); session.setAttribute( "foo", new EntityWithCollections() ); final Map<String, Object> deserialized = _transcoder.deserializeAttributes( _transcoder.serializeAttributes( session, session.getAttributesInternal() ) ); assertDeepEquals( deserialized, session.getAttributesInternal() ); } @Test( enabled = true ) public void testCyclicDependencies() throws Exception { final MemcachedBackupSession session = _manager.createEmptySession(); session.setValid( true ); session.setCreationTime( System.currentTimeMillis() ); getField( StandardSession.class, "lastAccessedTime" ).set( session, System.currentTimeMillis() + 100 ); session.setMaxInactiveInterval( 600 ); final Person p1 = createPerson( "foo bar", Gender.MALE, 42, "foo.bar@example.org", "foo.bar@example.com" ); final Person p2 = createPerson( "bar baz", Gender.FEMALE, 42, "bar.baz@example.org", "bar.baz@example.com" ); p1.addFriend( p2 ); p2.addFriend( p1 ); session.setAttribute( "person1", p1 ); session.setAttribute( "person2", p2 ); final byte[] bytes = _transcoder.serializeAttributes( session, session.getAttributesInternal() ); assertDeepEquals( session.getAttributesInternal(), _transcoder.deserializeAttributes( bytes ) ); } public static class EntityWithCollections { private final String[] _bars; private final List<String> _foos; private final Map<String, Integer> _bazens; public EntityWithCollections() { _bars = new String[] { "foo", "bar" }; _foos = new ArrayList<String>( Arrays.asList( "foo", "bar" ) ); _bazens = new HashMap<String, Integer>(); _bazens.put( "foo", 1 ); _bazens.put( "bar", 2 ); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode( _bars ); result = prime * result + ( ( _bazens == null ) ? 0 : _bazens.hashCode() ); result = prime * result + ( ( _foos == null ) ? 0 : _foos.hashCode() ); return result; } @Override public boolean equals( final Object obj ) { if ( this == obj ) { return true; } if ( obj == null ) { return false; } if ( getClass() != obj.getClass() ) { return false; } final EntityWithCollections other = (EntityWithCollections) obj; if ( !Arrays.equals( _bars, other._bars ) ) { return false; } if ( _bazens == null ) { if ( other._bazens != null ) { return false; } } else if ( !_bazens.equals( other._bazens ) ) { return false; } if ( _foos == null ) { if ( other._foos != null ) { return false; } } else if ( !_foos.equals( other._foos ) ) { return false; } return true; } } private Field getField( final Class<?> clazz, final String name ) throws NoSuchFieldException { final Field field = clazz.getDeclaredField( name ); field.setAccessible( true ); return field; } /* * person2=Person [_gender=FEMALE, _name=bar baz, _props={email0=Email * [_email=bar.baz@example.org, _name=bar baz], email1=Email * [_email=bar.baz@example.com, _name=bar baz]}], person1=Person * [_gender=MALE, _name=foo bar, _props={email0=Email * [_email=foo.bar@example.org, _name=foo bar], email1=Email * [_email=foo.bar@example.com, _name=foo bar]}]} * * but was: person2={name=bar baz, props={email0={name=bar baz, * email=bar.baz@example.org}, email1={name=bar baz, * email=bar.baz@example.com}}, gender=FEMALE} person1={name=foo bar, * props={email0={name=foo bar, email=foo.bar@example.org}, email1={name=foo * bar, email=foo.bar@example.com}}, gender=MALE}} */ private void assertDeepEquals( final Object one, final Object another ) throws Exception { assertDeepEquals( one, another, new IdentityHashMap<Object, Object>() ); } private void assertDeepEquals( final Object one, final Object another, final Map<Object, Object> alreadyChecked ) throws Exception { if ( one == another ) { return; } if ( one == null && another != null || one != null && another == null ) { Assert.fail( "One of both is null: " + one + ", " + another ); } if ( alreadyChecked.containsKey( one ) ) { return; } alreadyChecked.put( one, another ); Assert.assertEquals( one.getClass(), another.getClass() ); if ( one.getClass().isPrimitive() || one instanceof String || one instanceof Character || one instanceof Boolean ) { Assert.assertEquals( one, another ); return; } if ( Map.class.isAssignableFrom( one.getClass() ) ) { final Map<?, ?> m1 = (Map<?, ?>) one; final Map<?, ?> m2 = (Map<?, ?>) another; Assert.assertEquals( m1.size(), m2.size() ); for ( final Map.Entry<?, ?> entry : m1.entrySet() ) { assertDeepEquals( entry.getValue(), m2.get( entry.getKey() ) ); } return; } if ( Number.class.isAssignableFrom( one.getClass() ) ) { Assert.assertEquals( ( (Number) one ).longValue(), ( (Number) another ).longValue() ); return; } if ( one instanceof Currency ) { // Check that the transient field defaultFractionDigits is initialized correctly (that was issue #34) final Currency currency1 = ( Currency) one; final Currency currency2 = ( Currency) another; Assert.assertEquals( currency1.getCurrencyCode(), currency2.getCurrencyCode() ); Assert.assertEquals( currency1.getDefaultFractionDigits(), currency2.getDefaultFractionDigits() ); } Class<? extends Object> clazz = one.getClass(); while ( clazz != null ) { assertEqualDeclaredFields( clazz, one, another, alreadyChecked ); clazz = clazz.getSuperclass(); } } private void assertEqualDeclaredFields( final Class<? extends Object> clazz, final Object one, final Object another, final Map<Object, Object> alreadyChecked ) throws Exception, IllegalAccessException { for ( final Field field : clazz.getDeclaredFields() ) { field.setAccessible( true ); if ( !Modifier.isTransient( field.getModifiers() ) ) { assertDeepEquals( field.get( one ), field.get( another ), alreadyChecked ); } } } protected byte[] serialize( final Object o ) { if ( o == null ) { throw new NullPointerException( "Can't serialize null" ); } XMLObjectWriter writer = null; try { final ByteArrayOutputStream bos = new ByteArrayOutputStream(); writer = XMLObjectWriter.newInstance( bos ); final XMLReferenceResolver xmlReferenceResolver = new XMLReferenceResolver(); xmlReferenceResolver.setIdentifierAttribute( JavolutionTranscoder.REFERENCE_ATTRIBUTE_ID ); xmlReferenceResolver.setReferenceAttribute( JavolutionTranscoder.REFERENCE_ATTRIBUTE_REF_ID ); writer.setReferenceResolver( xmlReferenceResolver ); writer.setBinding( new ReflectionBinding( getClass().getClassLoader() ) ); writer.write( o, "session" ); writer.flush(); return bos.toByteArray(); } catch ( final Exception e ) { throw new IllegalArgumentException( "Non-serializable object", e ); } finally { try { writer.close(); } catch ( final XMLStreamException e ) { // fail silently } } } protected Object deserialize( final byte[] in ) { XMLObjectReader reader = null; try { final ByteArrayInputStream bis = new ByteArrayInputStream( in ); reader = XMLObjectReader.newInstance( bis ); final XMLReferenceResolver xmlReferenceResolver = new XMLReferenceResolver(); xmlReferenceResolver.setIdentifierAttribute( JavolutionTranscoder.REFERENCE_ATTRIBUTE_ID ); xmlReferenceResolver.setReferenceAttribute( JavolutionTranscoder.REFERENCE_ATTRIBUTE_REF_ID ); reader.setReferenceResolver( xmlReferenceResolver ); reader.setBinding( new ReflectionBinding( getClass().getClassLoader() ) ); if ( !reader.hasNext() ) { throw new IllegalStateException( "reader has no input" ); } return reader.read( "session" ); } catch ( final RuntimeException e ) { throw e; } catch ( final javolution.xml.stream.XMLStreamException e ) { throw new RuntimeException( e ); } finally { try { reader.close(); } catch ( final XMLStreamException e ) { // fail silently } } } }