11/*
2- * Copyright (C) 2008, 2009, 2011, 2012, 2013, 2015, 2016, 2018 XStream Committers.
2+ * Copyright (C) 2008, 2009, 2011, 2012, 2013, 2015, 2016, 2018, 2025 XStream Committers.
33 * All rights reserved.
44 *
55 * The software in this package is published under the terms of the BSD
2525import com .thoughtworks .xstream .annotations .XStreamConverter ;
2626import com .thoughtworks .xstream .annotations .XStreamConverters ;
2727import com .thoughtworks .xstream .annotations .XStreamInclude ;
28+ import com .thoughtworks .xstream .converters .SingleValueConverter ;
2829import com .thoughtworks .xstream .converters .basic .BooleanConverter ;
2930import com .thoughtworks .xstream .converters .collections .MapConverter ;
3031import com .thoughtworks .xstream .converters .extended .NamedCollectionConverter ;
@@ -117,7 +118,7 @@ public void testCanUseCurrentTypeAsParameter() {
117118 * converterCache on AnnotationMapper is functioning properly.
118119 */
119120 public void testSameConverterWithDifferentType () {
120- final Type value = new Type (new Decimal ("1.5" ), new Boolean ( true ) );
121+ final Type value = new Type (new Decimal ("1.5" ), Boolean . TRUE );
121122 final String expected = ""
122123 + "<type>\n "
123124 + " <decimal>1.5</decimal>\n "
@@ -137,6 +138,18 @@ public Decimal(final String str) {
137138 }
138139 }
139140
141+ public void testDerivedTypeWithParent () {
142+ final Type value = new Type (new Decimal ("1.5" ), Boolean .TRUE );
143+ final String expected = ""
144+ + "<type>\n "
145+ + " <decimal>1.5</decimal>\n "
146+ + " <boolean>true</boolean>\n "
147+ + " <agreement>yes</agreement>\n "
148+ + "</type>" ;
149+
150+ assertBothWays (value , expected );
151+ }
152+
140153 public static class Type {
141154 @ XStreamConverter (ToStringConverter .class )
142155 private Decimal decimal = null ;
@@ -154,7 +167,7 @@ public Type(final Decimal decimal, final Boolean bool) {
154167 }
155168
156169 public void testConverterRequiringNull () {
157- final Type value = new DerivedType (new Decimal ("1.5" ), new Boolean ( true ) , DerivedType .E .FOO );
170+ final Type value = new DerivedType (new Decimal ("1.5" ), Boolean . TRUE , DerivedType .E .FOO );
158171 final String expected = "<dtype boolean='true' agreement='yes' enum='FOO'>1.5</dtype>" .replace ('\'' , '"' );
159172 assertBothWays (value , expected );
160173 }
@@ -168,7 +181,7 @@ public MyType(final Decimal decimal, final Boolean bool) {
168181 }
169182
170183 public void testConverterWithSecondTypeParameter () {
171- final Type value = new DerivedType (new Decimal ("1.5" ), new Boolean ( true ) , DerivedType .E .FOO );
184+ final Type value = new DerivedType (new Decimal ("1.5" ), Boolean . TRUE , DerivedType .E .FOO );
172185 final String expected = "<dtype boolean='true' agreement='yes' enum='FOO'>1.5</dtype>" .replace ('\'' , '"' );
173186 assertBothWays (value , expected );
174187 }
@@ -178,7 +191,7 @@ public void testConverterWithSecondTypeParameter() {
178191 public static class DerivedType extends Type {
179192 public enum E {
180193 FOO , BAR
181- };
194+ }
182195
183196 @ XStreamAlias ("enum" )
184197 private final E e ;
@@ -190,7 +203,7 @@ public DerivedType(final Decimal decimal, final Boolean bool, final E e) {
190203 }
191204
192205 public void testConverterWithAllAttributes () {
193- final Type value = new DerivedType2 (new Decimal ("1.5" ), new Boolean ( true ) , DerivedType2 .E .FOO );
206+ final Type value = new DerivedType2 (new Decimal ("1.5" ), Boolean . TRUE , DerivedType2 .E .FOO );
194207 final String expected = "<dtype2 decimal='1.5' boolean='true' agreement='yes' enum='FOO'/>" .replace ('\'' , '"' );
195208 assertBothWays (value , expected );
196209 }
@@ -200,7 +213,7 @@ public void testConverterWithAllAttributes() {
200213 public static class DerivedType2 extends Type {
201214 public enum E {
202215 FOO , BAR
203- };
216+ }
204217
205218 @ XStreamAlias ("enum" )
206219 private final E e ;
@@ -258,7 +271,7 @@ public static class ContainsMap extends StandardObject {
258271
259272 public enum E {
260273 FOO , BAR
261- };
274+ }
262275
263276 @ XStreamConverter (value = NamedMapConverter .class , strings = {"issue" , "key" , "" }, types = {
264277 MyEnumMap .class , E .class , String .class }, booleans = {true , false }, useImplicitType = false )
@@ -276,15 +289,15 @@ public void testAnnotatedNamedMapConverterWithMultipleSameArguments() {
276289 map .put ("FOO" , "foo" );
277290 map .put ("BAR" , "bar" );
278291 final ContainsMap2 value = new ContainsMap2 (map );
279- final String expected = ( ""
292+ final String expected = ""
280293 + "<container-map>\n "
281294 + " <map>\n "
282295 + " <key>FOO</key>\n "
283296 + " <value>foo</value>\n "
284297 + " <key>BAR</key>\n "
285298 + " <value>bar</value>\n "
286299 + " </map>\n "
287- + "</container-map>" ). replace ( '\'' , '"' ) ;
300+ + "</container-map>" ;
288301 assertBothWays (value , expected );
289302 }
290303
@@ -308,14 +321,14 @@ public static class MyEnumMap extends LinkedHashMap<ContainsMap.E, String> {
308321 public void testAnnotatedNamedCollectionConverter () {
309322 final List <String > names = new ArrayList <>(Arrays .asList ("joe" , "joerg" , "mauro" ));
310323 final ContainsCollection container = new ContainsCollection (names );
311- final String expected = ( ""
324+ final String expected = ""
312325 + "<CollCont>\n "
313326 + " <names>\n "
314327 + " <name>joe</name>\n "
315328 + " <name>joerg</name>\n "
316329 + " <name>mauro</name>\n "
317330 + " </names>\n "
318- + "</CollCont>" ). replace ( '\'' , '"' ) ;
331+ + "</CollCont>" ;
319332 assertBothWays (container , expected );
320333 }
321334
@@ -330,4 +343,52 @@ public ContainsCollection(final List<String> names) {
330343 this .names = names ;
331344 }
332345 }
346+
347+ public void testAnnotatedConverterFromBaseClass () {
348+ xstream .processAnnotations (DerivedBase .class );
349+
350+ final List <Base > list = new ArrayList <>();
351+ list .add (new DerivedBase ());
352+ final String expected = "" //
353+ + "<list>\n "
354+ + " <dbase>DB</dbase>\n "
355+ + "</list>" ;
356+ assertBothWays (list , expected );
357+ }
358+
359+ public void testAutoDetectedAnnotatedConverterFromBaseClass () {
360+ xstream .autodetectAnnotations (true );
361+
362+ final List <Base > list = new ArrayList <>();
363+ list .add (new DerivedBase ());
364+ final String expected = "" //
365+ + "<list>\n "
366+ + " <dbase>DB</dbase>\n "
367+ + "</list>" ;
368+ assertBothWays (list , expected );
369+ }
370+
371+ public static class BaseConverter implements SingleValueConverter {
372+
373+ @ Override
374+ public boolean canConvert (final Class <?> type ) {
375+ return Base .class .isAssignableFrom (type );
376+ }
377+
378+ @ Override
379+ public String toString (final Object obj ) {
380+ return obj instanceof DerivedBase ? "DB" : "B" ;
381+ }
382+
383+ @ Override
384+ public Object fromString (final String str ) {
385+ return str .equals ("DB" ) ? new DerivedBase () : new Base ();
386+ }
387+ }
388+
389+ @ XStreamConverter (BaseConverter .class )
390+ public static class Base {}
391+
392+ @ XStreamAlias ("dbase" )
393+ public static class DerivedBase extends Base {}
333394}
0 commit comments