diff --git a/src/main/java/net/fortuna/ical4j/data/ContentHandlerContext.java b/src/main/java/net/fortuna/ical4j/data/ContentHandlerContext.java index b16276401..2c771be92 100644 --- a/src/main/java/net/fortuna/ical4j/data/ContentHandlerContext.java +++ b/src/main/java/net/fortuna/ical4j/data/ContentHandlerContext.java @@ -21,12 +21,15 @@ public class ContentHandlerContext { private List ignoredPropertyNames = Collections.emptyList(); + private boolean supressInvalidProperties; + public ContentHandlerContext withParameterFactorySupplier(Supplier>> parameterFactorySupplier) { ContentHandlerContext context = new ContentHandlerContext(); context.parameterFactorySupplier = parameterFactorySupplier; context.propertyFactorySupplier = this.propertyFactorySupplier; context.componentFactorySupplier = this.componentFactorySupplier; context.ignoredPropertyNames = this.ignoredPropertyNames; + context.supressInvalidProperties = this.supressInvalidProperties; return context; } @@ -36,6 +39,7 @@ public ContentHandlerContext withPropertyFactorySupplier(Supplier ignoredProper context.propertyFactorySupplier = this.propertyFactorySupplier; context.componentFactorySupplier = this.componentFactorySupplier; context.ignoredPropertyNames = ignoredPropertyNames; + context.supressInvalidProperties = this.supressInvalidProperties; + return context; + } + + public ContentHandlerContext withSupressInvalidProperties(boolean supressInvalidProperties) { + ContentHandlerContext context = new ContentHandlerContext(); + context.parameterFactorySupplier = this.parameterFactorySupplier; + context.propertyFactorySupplier = this.propertyFactorySupplier; + context.componentFactorySupplier = this.componentFactorySupplier; + context.ignoredPropertyNames = this.ignoredPropertyNames; + context.supressInvalidProperties = supressInvalidProperties; return context; } @@ -72,4 +88,8 @@ public Supplier>> getComponentFactorySupplier() { public List getIgnoredPropertyNames() { return ignoredPropertyNames; } + + public boolean isSupressInvalidProperties() { + return supressInvalidProperties; + } } diff --git a/src/main/java/net/fortuna/ical4j/data/DefaultContentHandler.java b/src/main/java/net/fortuna/ical4j/data/DefaultContentHandler.java index 01484fa4a..0da0325a8 100644 --- a/src/main/java/net/fortuna/ical4j/data/DefaultContentHandler.java +++ b/src/main/java/net/fortuna/ical4j/data/DefaultContentHandler.java @@ -156,7 +156,17 @@ public void propertyValue(String value) { public void endProperty(String name) throws URISyntaxException, ParseException, IOException { if (!context.getIgnoredPropertyNames().contains(name.toUpperCase())) { assertProperty(propertyBuilder); - Property property = propertyBuilder.build(); + Property property; + try { + property = propertyBuilder.build(); + } catch (URISyntaxException | ParseException | IOException e) { + if (context.isSupressInvalidProperties()) { + LOG.warn("Suppressing invalid property", e); + return; + } else { + throw e; + } + } if (propertyHasTzId) { propertiesWithTzId.add(property); @@ -168,7 +178,6 @@ public void endProperty(String name) throws URISyntaxException, ParseException, } else if (calendar != null) { calendar.getProperties().add(property); } - property = null; } } diff --git a/src/test/groovy/net/fortuna/ical4j/data/DefaultContentHandlerTest.groovy b/src/test/groovy/net/fortuna/ical4j/data/DefaultContentHandlerTest.groovy index ed9290f78..cfa0d49b3 100644 --- a/src/test/groovy/net/fortuna/ical4j/data/DefaultContentHandlerTest.groovy +++ b/src/test/groovy/net/fortuna/ical4j/data/DefaultContentHandlerTest.groovy @@ -69,4 +69,37 @@ class DefaultContentHandlerTest extends Specification { } } } + + def 'test supressed invalid properties'() { + given: 'a calendar reference' + def result + + and: 'a content handler instance with supressed invalid properties' + DefaultContentHandler contentHandler = [{result = it} as Consumer, + TimeZoneRegistryFactory.instance.createRegistry(), + new ContentHandlerContext().withSupressInvalidProperties(true)] + + when: 'a calendar is parsed' + contentHandler.startCalendar() + contentHandler.startComponent('vevent') + contentHandler.startProperty('dtstart') + contentHandler.parameter('value', 'DATE') + contentHandler.propertyValue('20181212') + contentHandler.endProperty('dtstart') + contentHandler.startProperty('dtend') + contentHandler.parameter('value', 'DATE') + contentHandler.propertyValue('20181213T120000Z') + contentHandler.endProperty('dtend') + contentHandler.endComponent('vevent') + contentHandler.endCalendar() + + then: 'the resulting calendar doesn\'t include suppressed properties' + result == new ContentBuilder().with { + calendar { + vevent { + dtstart '20181212', parameters: parameters { value 'DATE' } + } + } + } + } }