Skip to content

Commit

Permalink
[JBPM-9558] KIE using XStream does not complain on unknown fields
Browse files Browse the repository at this point in the history
Adding ElementIgnoringMapper custom implementation.
  • Loading branch information
fjtirado committed Jan 14, 2021
1 parent 62d7de2 commit 4171af3
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ public default String marshall(Object input, Map<String, Object> parameters) {

public <T> T unmarshall(String input, Class<T> type);

public default <T> T unmarshall(String input, Class<T> type, Map<String, Object> parameters) {
return unmarshall(input, type);
}

public void dispose();

public MarshallingFormat getFormat();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider;
import com.thoughtworks.xstream.mapper.ElementIgnoringMapper;
import com.thoughtworks.xstream.mapper.Mapper;
import com.thoughtworks.xstream.mapper.MapperWrapper;
import org.drools.core.runtime.help.impl.XStreamXML;
import org.kie.server.api.commands.CallContainerCommand;
Expand Down Expand Up @@ -81,10 +83,13 @@

public class XStreamMarshaller implements Marshaller {

public static final String XSTREAM_IGNORE_UNKNOWN = "ignoreUnknown";
private static final Logger logger = LoggerFactory.getLogger(XStreamMarshaller.class);
protected XStream xstream;
protected ClassLoader classLoader;
protected Map<String, Class> classNames = new HashMap<String, Class>();
protected Map<String, Class<?>> classNames = new HashMap<>();

private ThreadLocal<XStreamContext> xstreamContext = ThreadLocal.withInitial(XStreamContext::new);

// Optional marshaller extensions to handle new types / configure custom behavior
private static final List<XStreamMarshallerExtension> EXTENSIONS;
Expand Down Expand Up @@ -113,16 +118,42 @@ public XStreamMarshaller(Set<Class<?>> classes,
EXTENSIONS.forEach(ext -> ext.extend(this));
}

private static class XStreamContext {

private boolean ignoreUnknownElements;

public boolean isIgnoreUnknownElements() {
return ignoreUnknownElements;
}

public void setIgnoreUnknownElements(boolean ignoreUnknownElements) {
this.ignoreUnknownElements = ignoreUnknownElements;
}
}

protected class CustomElementIgnore extends ElementIgnoringMapper {

public CustomElementIgnore(Mapper wrapped) {
super(wrapped);
}

@Override
public boolean isIgnoredElement(String name) {
return xstreamContext.get().isIgnoreUnknownElements();
}
}

protected void buildMarshaller(Set<Class<?>> classes,
final ClassLoader classLoader) {
this.xstream = XStreamXML.newXStreamMarshaller(createNonTrustingXStream(
new PureJavaReflectionProvider(),
next -> {
return new MapperWrapper(chainMapperWrappers(new ArrayList<>(EXTENSIONS),
next)) {
public Class realClass(String elementName) {
new CustomElementIgnore(next))) {

Class customClass = classNames.get(elementName);
@Override
public Class<?> realClass(String elementName) {
Class<?> customClass = classNames.get(elementName);
if (customClass != null) {
return customClass;
}
Expand Down Expand Up @@ -151,7 +182,7 @@ protected void configureMarshaller(Set<Class<?>> classes,
this.xstream.denyTypes(voidDeny);

this.xstream.addPermission(new KieServerTypePermission(classes));
String classWildcards[] = {"org.kie.api.pmml.*", "org.kie.pmml.pmml_4_2.model.*"};
String[] classWildcards = {"org.kie.api.pmml.*", "org.kie.pmml.pmml_4_2.model.*"};
this.xstream.allowTypesByWildcard(classWildcards);

AbstractScoreXStreamConverter.registerScoreConverters(xstream);
Expand Down Expand Up @@ -220,12 +251,21 @@ public String marshall(Object objectInput) {
@Override
public <T> T unmarshall(String input,
Class<T> type) {
xstreamContext.get().setIgnoreUnknownElements(false);
return (T) xstream.fromXML(input);
}

@Override
public <T> T unmarshall(String input, Class<T> type, Map<String, Object> parameters) {
Object ignoreString = parameters.get(XSTREAM_IGNORE_UNKNOWN);
xstreamContext.get().setIgnoreUnknownElements(ignoreString != null && Boolean.parseBoolean(ignoreString
.toString()));
return (T) xstream.fromXML(input);
}

@Override
public void dispose() {
// nothing to do
xstreamContext.remove();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ public Marshaller build(Set<Class<?>> classes, MarshallingFormat format, ClassLo
return new XStreamMarshaller(classes, classLoader) {
@Override
protected void buildMarshaller(Set<Class<?>> classes, ClassLoader classLoader) {
xstream = XStreamUtils.createNonTrustingXStream(new PureJavaReflectionProvider(), new DomDriver("UTF-8", new XmlFriendlyNameCoder("_-", "_")));
xstream = XStreamUtils.createNonTrustingXStream(new PureJavaReflectionProvider(), new DomDriver("UTF-8", new XmlFriendlyNameCoder("_-", "_"))
, next -> new CustomElementIgnore(next));
xstream.addPermission(new WildcardTypePermission(new String[]{"org.kie.server.api.**"}));
String[] voidDeny = {"void.class", "Void.class"};
xstream.denyTypes(voidDeny);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Set;

import com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.UnknownFieldException;
import org.assertj.core.api.Assertions;
import org.drools.compiler.kie.builder.impl.InternalKieModule;
import org.drools.compiler.kie.builder.impl.MemoryKieModule;
Expand All @@ -55,10 +57,12 @@
import org.kie.server.api.marshalling.objects.AnotherMessage;
import org.kie.server.api.marshalling.objects.DateObject;
import org.kie.server.api.marshalling.objects.Message;
import org.kie.server.api.marshalling.xstream.XStreamMarshaller;
import org.kie.server.api.model.KieContainerResourceFilter;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

Expand Down Expand Up @@ -249,4 +253,30 @@ public void testUnmarshallDateObject() {
assertEquals(LocalTime.of(10, 10, 10), dateObject.getLocalTime());
assertEquals(OffsetDateTime.of(LocalDateTime.of(2017, 1, 1, 10, 10, 10), ZoneOffset.ofHours(1)), dateObject.getOffsetDateTime());
}

@Test
public void testUnmarshallDateObjectWithExtraField() {
String expectedString = "<date-object>\n" +
" <localDate>2017-01-01</localDate>\n" +
" <localDateTime>2017-01-01T10:10:10</localDateTime>\n" +
" <localTime>10:10:10</localTime>\n" +
" <offsetDateTime>2017-01-01T10:10:10+01:00</offsetDateTime>\n" +
" <unknownField>jojojojo</unknownField>\n" +
"</date-object>";
Set<Class<?>> extraClasses = new HashSet<Class<?>>();
extraClasses.add(DateObject.class);
Marshaller marshaller = MarshallerFactory.getMarshaller(extraClasses, MarshallingFormat.XSTREAM, getClass()
.getClassLoader());

assertThrows(UnknownFieldException.class, () -> marshaller.unmarshall(expectedString, DateObject.class));
DateObject dateObject = marshaller.unmarshall(expectedString, DateObject.class, Collections.singletonMap(
XStreamMarshaller.XSTREAM_IGNORE_UNKNOWN, Boolean.TRUE));
assertNotNull(dateObject);
assertEquals(LocalDate.of(2017, 1, 1), dateObject.getLocalDate());
assertEquals(LocalDateTime.of(2017, 1, 1, 10, 10, 10), dateObject.getLocalDateTime());
assertEquals(LocalTime.of(10, 10, 10), dateObject.getLocalTime());
assertEquals(OffsetDateTime.of(LocalDateTime.of(2017, 1, 1, 10, 10, 10), ZoneOffset.ofHours(1)), dateObject
.getOffsetDateTime());
assertThrows(UnknownFieldException.class, () -> marshaller.unmarshall(expectedString, DateObject.class));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ public <T> T unmarshal(String containerId, String data, String marshallingFormat
throw new IllegalArgumentException("No marshaller found for format " + format);
}

Object instance = marshaller.unmarshall(data, unmarshalType);
Object instance = marshaller.unmarshall(data, unmarshalType, MarshallingFormat.buildParameters(
marshallingFormat));

if (instance instanceof Wrapped) {
return (T) ((Wrapped) instance).unwrap();
Expand All @@ -126,7 +127,8 @@ public <T> T unmarshal(String data, String marshallingFormat, Class<T> unmarshal
serverMarshallers.put(format, marshaller);
}

Object instance = marshaller.unmarshall(data, unmarshalType);
Object instance = marshaller.unmarshall(data, unmarshalType, MarshallingFormat.buildParameters(
marshallingFormat));

if (instance instanceof Wrapped) {
return (T) ((Wrapped) instance).unwrap();
Expand Down

0 comments on commit 4171af3

Please sign in to comment.