diff --git a/src/main/java/net/fortuna/ical4j/model/component/VEvent.java b/src/main/java/net/fortuna/ical4j/model/component/VEvent.java index c80b23614..58c93bc2b 100644 --- a/src/main/java/net/fortuna/ical4j/model/component/VEvent.java +++ b/src/main/java/net/fortuna/ical4j/model/component/VEvent.java @@ -321,7 +321,7 @@ public ComponentList getComponents() { * {@inheritDoc} */ @Override - public final void validate(final boolean recurse) throws ValidationException { + public final ValidationResult validate(final boolean recurse) throws ValidationException { ValidationResult result = new ValidationResult(); // validate that getAlarms() only contains VAlarm components // final Iterator iterator = getAlarms().iterator(); @@ -342,8 +342,8 @@ public final void validate(final boolean recurse) throws ValidationException { if (status != null && !Status.VEVENT_TENTATIVE.getValue().equals(status.getValue()) && !Status.VEVENT_CONFIRMED.getValue().equals(status.getValue()) && !Status.VEVENT_CANCELLED.getValue().equals(status.getValue())) { - result.getErrors().add("Status property [" - + status + "] is not applicable for VEVENT"); + result.getEntries().add(new ValidationEntry("Status property [" + + status + "] is not applicable for VEVENT", ValidationEntry.Level.ERROR, getName())); } if (getProperty(Property.DTEND) != null) { @@ -378,9 +378,9 @@ else if (startValue != null && !Value.DATE_TIME.equals(startValue)) { startEndValueMismatch = true; } if (startEndValueMismatch) { - result.getErrors().add("Property [" + Property.DTEND + result.getEntries().add(new ValidationEntry("Property [" + Property.DTEND + "] must have the same [" + Parameter.VALUE - + "] as [" + Property.DTSTART + "]"); + + "] as [" + Property.DTSTART + "]", ValidationEntry.Level.ERROR, getName())); } } } @@ -391,6 +391,7 @@ else if (startValue != null && !Value.DATE_TIME.equals(startValue)) { if (result.hasErrors()) { throw new ValidationException(result); } + return result; } /** diff --git a/src/main/java/net/fortuna/ical4j/model/component/XComponent.java b/src/main/java/net/fortuna/ical4j/model/component/XComponent.java index b3d7f49ce..6da52fb80 100644 --- a/src/main/java/net/fortuna/ical4j/model/component/XComponent.java +++ b/src/main/java/net/fortuna/ical4j/model/component/XComponent.java @@ -34,6 +34,7 @@ import net.fortuna.ical4j.model.PropertyList; import net.fortuna.ical4j.model.property.Method; import net.fortuna.ical4j.util.CompatibilityHints; +import net.fortuna.ical4j.validate.ValidationEntry; import net.fortuna.ical4j.validate.ValidationException; import net.fortuna.ical4j.validate.ValidationResult; import net.fortuna.ical4j.validate.Validator; @@ -71,13 +72,13 @@ public XComponent(final String name, final PropertyList properties) { * {@inheritDoc} */ @Override - public final void validate(final boolean recurse) throws ValidationException { + public final ValidationResult validate(final boolean recurse) throws ValidationException { ValidationResult result = new ValidationResult(); if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION) && !getName().startsWith(EXPERIMENTAL_PREFIX)) { - result.getErrors().add("Experimental components must have the following prefix: " - + EXPERIMENTAL_PREFIX); + result.getEntries().add(new ValidationEntry("Experimental components must have the following prefix: " + + EXPERIMENTAL_PREFIX, ValidationEntry.Level.ERROR, getName())); } if (recurse) { @@ -86,6 +87,7 @@ public final void validate(final boolean recurse) throws ValidationException { if (result.hasErrors()) { throw new ValidationException(result); } + return result; } /** diff --git a/src/main/java/net/fortuna/ical4j/validate/CalendarValidatorImpl.java b/src/main/java/net/fortuna/ical4j/validate/CalendarValidatorImpl.java index 8fd696baa..5307dc8fc 100644 --- a/src/main/java/net/fortuna/ical4j/validate/CalendarValidatorImpl.java +++ b/src/main/java/net/fortuna/ical4j/validate/CalendarValidatorImpl.java @@ -35,26 +35,21 @@ public void validate(Calendar target) throws ValidationException { ValidationResult result = new ValidationResult(); for (ValidationRule rule : rules) { - boolean warnOnly = CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION) - && rule.isRelaxedModeSupported(); - - if (warnOnly) { - result.getWarnings().addAll(apply(rule, (PropertyContainer) target)); - } else { - result.getErrors().addAll(apply(rule, (PropertyContainer) target)); - } + result.getEntries().addAll(apply(rule, Calendar.VCALENDAR, (PropertyContainer) target)); } if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) { // require VERSION:2.0 for RFC2445.. if (!Version.VERSION_2_0.equals(target.getProperty(Property.VERSION))) { - result.getErrors().add("Unsupported Version: " + target.getProperty(Property.VERSION).getValue()); + result.getEntries().add(new ValidationEntry("Unsupported Version: " + target.getProperty(Property.VERSION).getValue(), + ValidationEntry.Level.ERROR, Calendar.VCALENDAR)); } } // must contain at least one component if (target.getComponents().isEmpty()) { - result.getErrors().add("Calendar must contain at least one component"); + result.getEntries().add(new ValidationEntry("Calendar must contain at least one component", + ValidationEntry.Level.ERROR, Calendar.VCALENDAR)); } // validate properties.. @@ -62,7 +57,8 @@ public void validate(Calendar target) throws ValidationException { boolean isCalendarProperty = calendarProperties.stream().filter(calProp -> calProp.isInstance(property)) != null; if (!(property instanceof XProperty) && !isCalendarProperty) { - result.getErrors().add("Invalid property: " + property.getName()); + result.getEntries().add(new ValidationEntry("Invalid property: " + property.getName(), + ValidationEntry.Level.ERROR, Calendar.VCALENDAR)); } } diff --git a/src/main/java/net/fortuna/ical4j/validate/ComponentValidator.java b/src/main/java/net/fortuna/ical4j/validate/ComponentValidator.java index 0f9982fb5..3d2c15fca 100644 --- a/src/main/java/net/fortuna/ical4j/validate/ComponentValidator.java +++ b/src/main/java/net/fortuna/ical4j/validate/ComponentValidator.java @@ -34,7 +34,6 @@ import net.fortuna.ical4j.model.Component; import net.fortuna.ical4j.model.ComponentList; import net.fortuna.ical4j.model.component.*; -import net.fortuna.ical4j.util.CompatibilityHints; import java.util.Arrays; import java.util.List; @@ -147,14 +146,7 @@ public void validate(T target) throws ValidationException { ValidationResult result = new ValidationResult(); for (ValidationRule rule : rules) { - boolean warnOnly = CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION) - && rule.isRelaxedModeSupported(); - - if (warnOnly) { - result.getWarnings().addAll(apply(rule, target)); - } else { - result.getErrors().addAll(apply(rule, target)); - } + result.getEntries().addAll(apply(rule, target.getName(), target)); } if (result.hasErrors()) { throw new ValidationException(result); diff --git a/src/main/java/net/fortuna/ical4j/validate/PropertyValidator.java b/src/main/java/net/fortuna/ical4j/validate/PropertyValidator.java index 9a2453a39..126b1ff8b 100644 --- a/src/main/java/net/fortuna/ical4j/validate/PropertyValidator.java +++ b/src/main/java/net/fortuna/ical4j/validate/PropertyValidator.java @@ -33,7 +33,6 @@ import net.fortuna.ical4j.model.Property; import net.fortuna.ical4j.model.property.*; -import net.fortuna.ical4j.util.CompatibilityHints; import java.util.Arrays; import java.util.List; @@ -141,14 +140,7 @@ public PropertyValidator(List rules) { public void validate(Property target) throws ValidationException { ValidationResult result = new ValidationResult(); for (ValidationRule rule : rules) { - boolean warnOnly = CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION) - && rule.isRelaxedModeSupported(); - - if (warnOnly) { - result.getWarnings().addAll(apply(rule, target)); - } else { - result.getErrors().addAll(apply(rule, target)); - } + result.getEntries().addAll(apply(rule, target.getName(), target)); } if (result.hasErrors()) { throw new ValidationException(result); diff --git a/src/main/java/net/fortuna/ical4j/validate/ValidationEntry.java b/src/main/java/net/fortuna/ical4j/validate/ValidationEntry.java new file mode 100644 index 000000000..35e869ccf --- /dev/null +++ b/src/main/java/net/fortuna/ical4j/validate/ValidationEntry.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2022, Ben Fortuna + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * o Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * o Neither the name of Ben Fortuna nor the names of any other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.fortuna.ical4j.validate; + +public class ValidationEntry { + + public enum Level { + ERROR, WARNING, INFO + } + + private final String message; + + private final Level level; + + private final String context; + + public ValidationEntry(String message, Level level, String context) { + this.message = message; + this.level = level; + this.context = context; + } + + public ValidationEntry(ValidationRule rule, String context, String...instances) { + this.message = rule.getMessage(instances); + this.level = rule.getLevel(); + this.context = context; + } + + public String getMessage() { + return message; + } + + public Level getLevel() { + return level; + } + + public String getContext() { + return context; + } + + @Override + public String toString() { + return "ValidationEntry{" + + "message='" + message + '\'' + + ", level=" + level + + ", context='" + context + '\'' + + '}'; + } +} diff --git a/src/main/java/net/fortuna/ical4j/validate/ValidationException.java b/src/main/java/net/fortuna/ical4j/validate/ValidationException.java index 27ded85d7..e550c069c 100644 --- a/src/main/java/net/fortuna/ical4j/validate/ValidationException.java +++ b/src/main/java/net/fortuna/ical4j/validate/ValidationException.java @@ -67,7 +67,7 @@ public ValidationException(ValidationResult result) { * @param message a message */ public ValidationException(final String message) { - this(new ValidationResult(message)); + this(new ValidationResult(new ValidationEntry(message, ValidationEntry.Level.ERROR, null))); } /** @@ -76,7 +76,8 @@ public ValidationException(final String message) { * @param args message arguments */ public ValidationException(final String message, Object[] args) { - this(new ValidationResult(MessageFormat.format(message, args))); + this(new ValidationResult(new ValidationEntry(MessageFormat.format(message, args), + ValidationEntry.Level.ERROR, null))); } public ValidationResult getResult() { diff --git a/src/main/java/net/fortuna/ical4j/validate/ValidationResult.java b/src/main/java/net/fortuna/ical4j/validate/ValidationResult.java index 6727b7fe6..8d7f1ed6c 100644 --- a/src/main/java/net/fortuna/ical4j/validate/ValidationResult.java +++ b/src/main/java/net/fortuna/ical4j/validate/ValidationResult.java @@ -42,34 +42,24 @@ */ public final class ValidationResult { - private final List errors = new ArrayList<>(); + private final List entries = new ArrayList<>(); - private final List warnings = new ArrayList<>(); - - public ValidationResult() { - } - - public ValidationResult(String...errors) { - this.errors.addAll(Arrays.asList(errors)); - } - - public List getErrors() { - return errors; + public ValidationResult(ValidationEntry...entries) { + this.entries.addAll(Arrays.asList(entries)); } - public List getWarnings() { - return warnings; + public List getEntries() { + return entries; } public boolean hasErrors() { - return !errors.isEmpty(); + return entries.stream().anyMatch(e -> e.getLevel() == ValidationEntry.Level.ERROR); } @Override public String toString() { return "ValidationResult{" + - "errors=" + errors + - ", warnings=" + warnings + + "entries=" + entries + '}'; } } diff --git a/src/main/java/net/fortuna/ical4j/validate/component/AvailableValidator.java b/src/main/java/net/fortuna/ical4j/validate/component/AvailableValidator.java index 7a5b96d6e..a2ca1ed33 100644 --- a/src/main/java/net/fortuna/ical4j/validate/component/AvailableValidator.java +++ b/src/main/java/net/fortuna/ical4j/validate/component/AvailableValidator.java @@ -39,10 +39,7 @@ import net.fortuna.ical4j.model.parameter.Value; import net.fortuna.ical4j.model.property.DtEnd; import net.fortuna.ical4j.model.property.DtStart; -import net.fortuna.ical4j.validate.ComponentValidator; -import net.fortuna.ical4j.validate.ValidationException; -import net.fortuna.ical4j.validate.ValidationResult; -import net.fortuna.ical4j.validate.Validator; +import net.fortuna.ical4j.validate.*; public class AvailableValidator implements Validator { @@ -59,7 +56,8 @@ public void validate(Available target) throws ValidationException { */ final DtStart start = target.getProperty(Property.DTSTART); if (Value.DATE.equals(start.getParameter(Parameter.VALUE))) { - result.getErrors().add("Property [" + Property.DTSTART + "] must be a " + Value.DATE_TIME); + result.getEntries().add(new ValidationEntry("Property [" + Property.DTSTART + "] must be a " + Value.DATE_TIME, + ValidationEntry.Level.ERROR, target.getName())); } /* @@ -72,7 +70,8 @@ public void validate(Available target) throws ValidationException { final DtEnd end = target.getProperty(Property.DTEND); /* Must be DATE_TIME */ if (end != null && Value.DATE.equals(end.getParameter(Parameter.VALUE))) { - result.getErrors().add("Property [" + Property.DTEND + "] must be a " + Value.DATE_TIME); + result.getEntries().add(new ValidationEntry("Property [" + Property.DTEND + "] must be a " + Value.DATE_TIME, + ValidationEntry.Level.ERROR, target.getName())); } /* diff --git a/src/main/java/net/fortuna/ical4j/validate/component/VAvailabilityValidator.java b/src/main/java/net/fortuna/ical4j/validate/component/VAvailabilityValidator.java index 9a2fe0eee..3a48e60e4 100644 --- a/src/main/java/net/fortuna/ical4j/validate/component/VAvailabilityValidator.java +++ b/src/main/java/net/fortuna/ical4j/validate/component/VAvailabilityValidator.java @@ -39,10 +39,7 @@ import net.fortuna.ical4j.model.parameter.Value; import net.fortuna.ical4j.model.property.DtEnd; import net.fortuna.ical4j.model.property.DtStart; -import net.fortuna.ical4j.validate.ComponentValidator; -import net.fortuna.ical4j.validate.ValidationException; -import net.fortuna.ical4j.validate.ValidationResult; -import net.fortuna.ical4j.validate.Validator; +import net.fortuna.ical4j.validate.*; public class VAvailabilityValidator implements Validator { @@ -70,13 +67,15 @@ public void validate(VAvailability target) throws ValidationException { */ final DtStart start = target.getProperty(Property.DTSTART); if (Value.DATE.equals(start.getParameter(Parameter.VALUE))) { - result.getErrors().add("Property [" + Property.DTSTART + "] must be a " + Value.DATE_TIME); + result.getEntries().add(new ValidationEntry("Property [" + Property.DTSTART + "] must be a " + Value.DATE_TIME, + ValidationEntry.Level.ERROR, target.getName())); } /* Must be DATE_TIME */ final DtEnd end = target.getProperty(Property.DTEND); if (end != null && Value.DATE.equals(end.getParameter(Parameter.VALUE))) { - result.getErrors().add("Property [" + Property.DTEND + "] must be a " + Value.DATE_TIME); + result.getEntries().add(new ValidationEntry("Property [" + Property.DTEND + "] must be a " + Value.DATE_TIME, + ValidationEntry.Level.ERROR, target.getName())); } if (result.hasErrors()) { diff --git a/src/main/java/net/fortuna/ical4j/validate/component/VFreeBusyValidator.java b/src/main/java/net/fortuna/ical4j/validate/component/VFreeBusyValidator.java index 804637e44..88b6cc8e0 100644 --- a/src/main/java/net/fortuna/ical4j/validate/component/VFreeBusyValidator.java +++ b/src/main/java/net/fortuna/ical4j/validate/component/VFreeBusyValidator.java @@ -37,10 +37,7 @@ import net.fortuna.ical4j.model.component.VFreeBusy; import net.fortuna.ical4j.model.property.DtEnd; import net.fortuna.ical4j.model.property.DtStart; -import net.fortuna.ical4j.validate.ComponentValidator; -import net.fortuna.ical4j.validate.ValidationException; -import net.fortuna.ical4j.validate.ValidationResult; -import net.fortuna.ical4j.validate.Validator; +import net.fortuna.ical4j.validate.*; public class VFreeBusyValidator implements Validator { @@ -58,7 +55,8 @@ public void validate(VFreeBusy target) throws ValidationException { // start date and time for the free or busy time information. The time // MUST be specified in UTC time. if (dtStart != null && !dtStart.isUtc()) { - result.getErrors().add("DTSTART must be specified in UTC time"); + result.getEntries().add(new ValidationEntry("DTSTART must be specified in UTC time", + ValidationEntry.Level.ERROR, target.getName())); } final DtEnd dtEnd = target.getProperty(Property.DTEND); @@ -70,13 +68,15 @@ public void validate(VFreeBusy target) throws ValidationException { // MUST be specified in the UTC time format. The value MUST be later in // time than the value of the "DTSTART" property. if (dtEnd != null && !dtEnd.isUtc()) { - result.getErrors().add("DTEND must be specified in UTC time"); + result.getEntries().add(new ValidationEntry("DTEND must be specified in UTC time", + ValidationEntry.Level.ERROR, target.getName())); } if (dtStart != null && dtEnd != null && !dtStart.getDate().before(dtEnd.getDate())) { - result.getErrors().add("Property [" + Property.DTEND - + "] must be later in time than [" + Property.DTSTART + "]"); + result.getEntries().add(new ValidationEntry("Property [" + Property.DTEND + + "] must be later in time than [" + Property.DTSTART + "]", ValidationEntry.Level.ERROR, + target.getName())); } if (result.hasErrors()) { throw new ValidationException(result); diff --git a/src/main/java/net/fortuna/ical4j/validate/property/DatePropertyValidator.java b/src/main/java/net/fortuna/ical4j/validate/property/DatePropertyValidator.java index 5b246e655..d909b35ce 100644 --- a/src/main/java/net/fortuna/ical4j/validate/property/DatePropertyValidator.java +++ b/src/main/java/net/fortuna/ical4j/validate/property/DatePropertyValidator.java @@ -37,10 +37,7 @@ import net.fortuna.ical4j.model.Parameter; import net.fortuna.ical4j.model.parameter.Value; import net.fortuna.ical4j.model.property.DateProperty; -import net.fortuna.ical4j.validate.ParameterValidator; -import net.fortuna.ical4j.validate.ValidationException; -import net.fortuna.ical4j.validate.ValidationResult; -import net.fortuna.ical4j.validate.Validator; +import net.fortuna.ical4j.validate.*; public class DatePropertyValidator implements Validator { @@ -72,8 +69,9 @@ public void validate(T target) throws ValidationException { if (target.getDate() instanceof DateTime) { if (value != null && !Value.DATE_TIME.equals(value)) { - result.getErrors().add("VALUE parameter [" + value - + "] is invalid for DATE-TIME instance"); + result.getEntries().add(new ValidationEntry("VALUE parameter [" + value + + "] is invalid for DATE-TIME instance", ValidationEntry.Level.ERROR, + target.getName())); } final DateTime dateTime = (DateTime) target.getDate(); @@ -84,18 +82,21 @@ public void validate(T target) throws ValidationException { && (tzId == null || !tzId.getValue().equals( dateTime.getTimeZone().getID()))) { - result.getErrors().add("TZID parameter [" + tzId + result.getEntries().add(new ValidationEntry("TZID parameter [" + tzId + "] does not match the timezone [" - + dateTime.getTimeZone().getID() + "]"); + + dateTime.getTimeZone().getID() + "]", ValidationEntry.Level.ERROR, + target.getName())); } } else if (target.getDate() != null) { if (value == null) { - result.getErrors().add("VALUE parameter [" + Value.DATE - + "] must be specified for DATE instance"); + result.getEntries().add(new ValidationEntry("VALUE parameter [" + Value.DATE + + "] must be specified for DATE instance", ValidationEntry.Level.ERROR, + target.getName())); } else if (!Value.DATE.equals(value)) { - result.getErrors().add("VALUE parameter [" + value - + "] is invalid for DATE instance"); + result.getEntries().add(new ValidationEntry("VALUE parameter [" + value + + "] is invalid for DATE instance", ValidationEntry.Level.ERROR, + target.getName())); } } if (result.hasErrors()) { diff --git a/src/main/java/net/fortuna/ical4j/validate/property/StructuredDataValidator.java b/src/main/java/net/fortuna/ical4j/validate/property/StructuredDataValidator.java index 0af469720..2a6f3ad18 100644 --- a/src/main/java/net/fortuna/ical4j/validate/property/StructuredDataValidator.java +++ b/src/main/java/net/fortuna/ical4j/validate/property/StructuredDataValidator.java @@ -36,7 +36,6 @@ import net.fortuna.ical4j.model.property.StructuredData; import net.fortuna.ical4j.validate.PropertyValidator; import net.fortuna.ical4j.validate.ValidationException; -import net.fortuna.ical4j.validate.ValidationResult; import net.fortuna.ical4j.validate.Validator; import net.fortuna.ical4j.validate.schema.SchemaValidatorFactory; @@ -51,7 +50,7 @@ public void validate(StructuredData target) throws ValidationException { try { SchemaValidatorFactory.newInstance(target.getParameter(SCHEMA)).validate(target); } catch (org.everit.json.schema.ValidationException e) { - throw new ValidationException(new ValidationResult(e.getErrorMessage())); + throw new ValidationException(e.getErrorMessage()); } } } diff --git a/src/main/java/net/fortuna/ical4j/validate/property/UtcPropertyValidator.java b/src/main/java/net/fortuna/ical4j/validate/property/UtcPropertyValidator.java index 3c9cf1609..0c5893619 100644 --- a/src/main/java/net/fortuna/ical4j/validate/property/UtcPropertyValidator.java +++ b/src/main/java/net/fortuna/ical4j/validate/property/UtcPropertyValidator.java @@ -35,6 +35,7 @@ import net.fortuna.ical4j.model.DateTime; import net.fortuna.ical4j.model.property.UtcProperty; +import net.fortuna.ical4j.validate.ValidationEntry; import net.fortuna.ical4j.validate.ValidationException; import net.fortuna.ical4j.validate.ValidationResult; @@ -45,14 +46,16 @@ public void validate(T target) throws ValidationException { super.validate(target); ValidationResult result = new ValidationResult(); if (target.getDate() != null && !(target.getDate() instanceof DateTime)) { - result.getErrors().add("Property must have a DATE-TIME value"); + result.getEntries().add(new ValidationEntry("Property must have a DATE-TIME value", + ValidationEntry.Level.ERROR, target.getName())); } final DateTime dateTime = (DateTime) target.getDate(); if (dateTime != null && !dateTime.isUtc()) { - result.getErrors().add(target.getName() + - ": DATE-TIME value must be specified in UTC time"); + result.getEntries().add(new ValidationEntry(target.getName() + + ": DATE-TIME value must be specified in UTC time", ValidationEntry.Level.ERROR, + target.getName())); } if (result.hasErrors()) { throw new ValidationException(result);