Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RecordConverter: Do not throw ClassNotFoundException when "class" attribute is absent #351

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ private void writeItem(RecordComponent recordComponent, Object compValue, Marsha
*/
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
final Class<?> aRecord = findClass(reader);
final Class<?> aRecord = context.getRequiredType();
if (!isRecord(aRecord)) {
throw new ConversionException(aRecord + " is not a record");
}
Expand Down Expand Up @@ -225,12 +225,6 @@ private static Class<?> classForName(String className) {
}
}

private static Class<?> findClass(HierarchicalStreamReader reader) {
String c = reader.getAttribute("class");
String className = c != null ? c : reader.getNodeName();
return classForName(className);
}

/**
* Invokes the canonical constructor of a record class with the given argument values.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,17 @@
import com.thoughtworks.acceptance.AbstractAcceptanceTest;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.ConversionException;

import com.thoughtworks.xstream.io.xml.StaxDriver;
import com.thoughtworks.xstream.security.AnyTypePermission;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.IntStream;
import junit.framework.Assert;


/**
Expand Down Expand Up @@ -296,4 +305,72 @@ static <T extends Throwable> T expectThrows(Class<T> throwableClass, Runnable ta
return throwableClass.cast(cause);
}
}

public static final class MyObj
{
SerializableRecord field1 = new SerializableRecord( 1, 2 );
Object field2 = new SerializableRecord( 1, 2 );
Object field3 = new Object[] { new SerializableRecord( 1, 2 ) };

NotSerializableRecord field4 = new NotSerializableRecord( 1, 2 );
Object field5 = new NotSerializableRecord( 1, 2 );
Object field6 = new Object[] { new NotSerializableRecord( 1, 2 ) };

@Override
public boolean equals(Object o)
{
if ( this == o )
{
return true;
}
if ( o == null || getClass() != o.getClass() )
{
return false;
}
final MyObj myObj = (MyObj) o;
return Objects.equals( field1, myObj.field1 ) &&
Objects.equals( field2, myObj.field2 ) &&
Arrays.equals( (Object[]) field3, (Object[]) myObj.field3 ) &&
Objects.equals( field4, myObj.field4 ) &&
Objects.equals( field5, myObj.field5 ) &&
Arrays.equals( (Object[]) field6, (Object[]) myObj.field6 );
}

@Override
public int hashCode()
{
return Objects.hash( field1, field2, field3, field4, field5, field6 );
}
}

public record NotSerializableRecord(int a, int b) {}
public record SerializableRecord(int a, int b) implements Serializable {}

public void testMissingClassAttributeDoesNotCauseCrash()
{
final MyObj in = new MyObj();

final XStream xstream = new XStream( new StaxDriver() );
xstream.addPermission( AnyTypePermission.ANY);

final ByteArrayOutputStream bos = new ByteArrayOutputStream();
xstream.toXML( in, bos );
final String expected = """
<?xml version='1.0' encoding='UTF-8'?><com.thoughtworks.xstream.converters.extended.RecordConverterTest_-MyObj>
<field1><a>1</a><b>2</b></field1><field2 class="com.thoughtworks.xstream.converters.extended.RecordConverterTest$SerializableRecord">
<a>1</a><b>2</b></field2><field3 class="object-array">
<com.thoughtworks.xstream.converters.extended.RecordConverterTest_-SerializableRecord><a>1</a><b>2</b>
</com.thoughtworks.xstream.converters.extended.RecordConverterTest_-SerializableRecord></field3><field4><a>1</a>
<b>2</b></field4><field5 class="com.thoughtworks.xstream.converters.extended.RecordConverterTest$NotSerializableRecord">
<a>1</a><b>2</b></field5><field6 class="object-array">
<com.thoughtworks.xstream.converters.extended.RecordConverterTest_-NotSerializableRecord><a>1</a><b>2</b>
</com.thoughtworks.xstream.converters.extended.RecordConverterTest_-NotSerializableRecord></field6>
</com.thoughtworks.xstream.converters.extended.RecordConverterTest_-MyObj>
""";
final String actual = bos.toString( StandardCharsets.UTF_8 );
Assert.assertEquals( expected.replace("\n", ""), actual );

final Object out = xstream.fromXML( new ByteArrayInputStream( bos.toByteArray() ) );
Assert.assertEquals( in, out );
}
}