Use new ooxml lib

This commit is contained in:
Clément Fournier
2022-04-13 19:36:28 +02:00
parent 95b57dcb28
commit a5f9ed8f7e
15 changed files with 313 additions and 236 deletions

View File

@ -124,7 +124,7 @@
<dependency>
<groupId>com.github.oowekyala.ooxml</groupId>
<artifactId>nice-xml-messages</artifactId>
<version>1.0-SNAPSHOT</version>
<version>2.0-SNAPSHOT</version>
</dependency>
<dependency>

View File

@ -0,0 +1,19 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.internal.util.xml;
import net.sourceforge.pmd.util.log.MessageReporter;
import com.github.oowekyala.ooxml.messages.XmlException;
import com.github.oowekyala.ooxml.messages.XmlMessageReporter;
/**
* @author Clément Fournier
*/
public interface PmdXmlReporter extends XmlMessageReporter<MessageReporter> {
void addExceptionToThrowLater(XmlException e);
}

View File

@ -14,8 +14,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import com.github.oowekyala.ooxml.messages.XmlErrorReporter;
import org.w3c.dom.Node;
/**
@ -36,21 +35,21 @@ public class SchemaConstant {
return e.hasAttribute(name) ? Boolean.parseBoolean(attr) : defaultValue;
}
public @NonNull String getAttributeOrThrow(Element element, XmlErrorReporter err) {
public @NonNull String getAttributeOrThrow(Element element, PmdXmlReporter err) {
String attribute = element.getAttribute(name);
if (!element.hasAttribute(name)) {
throw err.error(element, XmlErrorMessages.ERR__MISSING_REQUIRED_ATTRIBUTE, name);
throw err.at(element).error(XmlErrorMessages.ERR__MISSING_REQUIRED_ATTRIBUTE, name);
}
return attribute;
}
public @NonNull String getNonBlankAttributeOrThrow(Element element, XmlErrorReporter err) {
public @NonNull String getNonBlankAttributeOrThrow(Element element, PmdXmlReporter err) {
String attribute = element.getAttribute(name);
if (!element.hasAttribute(name)) {
throw err.error(element, XmlErrorMessages.ERR__MISSING_REQUIRED_ATTRIBUTE, name);
throw err.at(element).error(XmlErrorMessages.ERR__MISSING_REQUIRED_ATTRIBUTE, name);
} else if (StringUtils.isBlank(attribute)) {
throw err.error(element, XmlErrorMessages.ERR__BLANK_REQUIRED_ATTRIBUTE, name);
throw err.at(element).error(XmlErrorMessages.ERR__BLANK_REQUIRED_ATTRIBUTE, name);
}
return attribute;
}
@ -73,16 +72,16 @@ public class SchemaConstant {
.collect(Collectors.toList());
}
public List<Element> getElementChildrenNamedReportOthers(Element elt, XmlErrorReporter err) {
public List<Element> getElementChildrenNamedReportOthers(Element elt, PmdXmlReporter err) {
return XmlUtil.getElementChildrenNamedReportOthers(elt, setOf(name), err)
.collect(Collectors.toList());
}
public Element getSingleChildIn(Element elt, XmlErrorReporter err) {
public Element getSingleChildIn(Element elt, PmdXmlReporter err) {
return XmlUtil.getSingleChildIn(elt, true, err, setOf(name));
}
public Element getOptChildIn(Element elt, XmlErrorReporter err) {
public Element getOptChildIn(Element elt, PmdXmlReporter err) {
return XmlUtil.getSingleChildIn(elt, false, err, setOf(name));
}
@ -106,4 +105,7 @@ public class SchemaConstant {
}
public boolean isElementWithName(Node node) {
return node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals(name);
}
}

View File

@ -21,6 +21,15 @@ public final class SchemaConstants {
public static final SchemaConstant DEPRECATED = new SchemaConstant("deprecated");
// ruleset
public static final SchemaConstant EXCLUDE_PATTERN = new SchemaConstant("exclude-pattern");
public static final SchemaConstant INCLUDE_PATTERN = new SchemaConstant("include-pattern");
public static final SchemaConstant RULE = new SchemaConstant("rule");
public static final SchemaConstant EXCLUDE = new SchemaConstant("exclude");
public static final SchemaConstant PRIORITY = new SchemaConstant("priority");
private SchemaConstants() {
// utility class
}

View File

@ -21,7 +21,6 @@ import org.w3c.dom.Node;
import net.sourceforge.pmd.properties.xml.XmlMapper;
import com.github.oowekyala.ooxml.DomUtils;
import com.github.oowekyala.ooxml.messages.XmlErrorReporter;
public final class XmlUtil {
@ -39,13 +38,13 @@ public final class XmlUtil {
return getElementChildren(parent).filter(e -> names.contains(e.getTagName()));
}
public static Stream<Element> getElementChildrenNamedReportOthers(Element parent, Set<String> names, XmlErrorReporter err) {
public static Stream<Element> getElementChildrenNamedReportOthers(Element parent, Set<String> names, PmdXmlReporter err) {
return getElementChildren(parent)
.map(it -> {
if (names.contains(it.getTagName())) {
return it;
} else {
err.warn(it, IGNORED__UNEXPECTED_ELEMENT, it.getTagName(), formatPossibleNames(names));
err.at(it).warn(IGNORED__UNEXPECTED_ELEMENT, it.getTagName(), formatPossibleNames(names));
return null;
}
}).filter(Objects::nonNull);
@ -55,10 +54,10 @@ public final class XmlUtil {
return getElementChildren(parent).filter(e -> name.equals(e.getTagName()));
}
public static <T> T expectElement(XmlErrorReporter err, Element elt, XmlMapper<T> syntax) {
public static <T> T expectElement(PmdXmlReporter err, Element elt, XmlMapper<T> syntax) {
if (!syntax.getReadElementNames().contains(elt.getTagName())) {
err.warn(elt, "Wrong name, expected " + formatPossibleNames(syntax.getReadElementNames()));
err.at(elt).warn("Wrong name, expected " + formatPossibleNames(syntax.getReadElementNames()));
} else {
return syntax.fromXml(elt, err);
}
@ -67,28 +66,28 @@ public final class XmlUtil {
}
public static List<Element> getChildrenExpectSingleName(Element elt, String name, XmlErrorReporter err) {
public static List<Element> getChildrenExpectSingleName(Element elt, String name, PmdXmlReporter err) {
return XmlUtil.getElementChildren(elt).peek(it -> {
if (!it.getTagName().equals(name)) {
err.warn(it, IGNORED__UNEXPECTED_ELEMENT, it.getTagName(), name);
err.at(it).warn(IGNORED__UNEXPECTED_ELEMENT, it.getTagName(), name);
}
}).collect(Collectors.toList());
}
public static Element getSingleChildIn(Element elt, boolean throwOnMissing, XmlErrorReporter err, Set<String> names) {
public static Element getSingleChildIn(Element elt, boolean throwOnMissing, PmdXmlReporter err, Set<String> names) {
List<Element> children = getElementChildrenNamed(elt, names).collect(Collectors.toList());
if (children.size() == 1) {
return children.get(0);
} else if (children.isEmpty()) {
if (throwOnMissing) {
throw err.error(elt, ERR__MISSING_REQUIRED_ELEMENT, formatPossibleNames(names));
throw err.at(elt).error(ERR__MISSING_REQUIRED_ELEMENT, formatPossibleNames(names));
} else {
return null;
}
} else {
for (int i = 1; i < children.size(); i++) {
Element child = children.get(i);
err.warn(child, IGNORED__DUPLICATE_CHILD_ELEMENT, child.getTagName());
err.at(child).warn(IGNORED__DUPLICATE_CHILD_ELEMENT, child.getTagName());
}
return children.get(0);
}

View File

@ -10,19 +10,18 @@ import java.util.Set;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.w3c.dom.Element;
import net.sourceforge.pmd.internal.util.xml.PmdXmlReporter;
import net.sourceforge.pmd.internal.util.xml.XmlErrorMessages;
import net.sourceforge.pmd.properties.constraints.PropertyConstraint;
import net.sourceforge.pmd.util.CollectionUtil;
import com.github.oowekyala.ooxml.messages.XmlErrorReporter;
/**
* Decorates an XmlMapper with some {@link PropertyConstraint}s.
* Those are checked when the value is parsed. This is used to
* report errors on the most specific failing element.
*
* <p>Note that this is the only XmlMapper that *applies* constraints
* in {@link #fromXml(Element, XmlErrorReporter)}. A {@link SeqSyntax}
* in {@link #fromXml(Element, PmdXmlReporter)}. A {@link SeqSyntax}
* or {@link OptionalSyntax} may return some constraints in {@link #getConstraints()}
* that are derived from the constraints of the item, yet not check them
* on elements (they will be applied on each element by the {@link XmlMapper}
@ -40,13 +39,13 @@ class ConstraintDecorator<T> extends XmlMapper<T> {
}
@Override
public T fromXml(Element element, XmlErrorReporter err) {
public T fromXml(Element element, PmdXmlReporter err) {
T t = xmlMapper.fromXml(element, err);
XmlSyntaxUtils.checkConstraintsThrow(
t,
constraints,
s -> err.error(element, XmlErrorMessages.ERR__CONSTRAINT_NOT_SATISFIED, s)
s -> err.at(element).error(XmlErrorMessages.ERR__CONSTRAINT_NOT_SATISFIED, s)
);
return t;

View File

@ -15,13 +15,12 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.w3c.dom.Element;
import net.sourceforge.pmd.internal.util.xml.PmdXmlReporter;
import net.sourceforge.pmd.internal.util.xml.XmlErrorMessages;
import net.sourceforge.pmd.internal.util.xml.XmlUtil;
import net.sourceforge.pmd.properties.constraints.PropertyConstraint;
import net.sourceforge.pmd.util.CollectionUtil;
import com.github.oowekyala.ooxml.messages.XmlErrorReporter;
/**
* A set of syntaxes for read and write. One special syntax is designated
* as the one used to write elements, the others are used to read.
@ -122,10 +121,10 @@ final class MapperSet<T> extends XmlMapper<T> {
}
@Override
public T fromXml(Element element, XmlErrorReporter err) {
public T fromXml(Element element, PmdXmlReporter err) {
XmlMapper<T> syntax = readIndex.get(element.getTagName());
if (syntax == null) {
throw err.error(element, XmlErrorMessages.ERR__UNEXPECTED_ELEMENT, element.getTagName(), XmlUtil.formatPossibleNames(readIndex.keySet()));
throw err.at(element).error(XmlErrorMessages.ERR__UNEXPECTED_ELEMENT, element.getTagName(), XmlUtil.formatPossibleNames(readIndex.keySet()));
} else {
return syntax.fromXml(element, err);
}

View File

@ -13,11 +13,10 @@ import java.util.stream.Collectors;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.w3c.dom.Element;
import net.sourceforge.pmd.internal.util.xml.PmdXmlReporter;
import net.sourceforge.pmd.properties.constraints.PropertyConstraint;
import net.sourceforge.pmd.util.CollectionUtil;
import com.github.oowekyala.ooxml.messages.XmlErrorReporter;
/**
* Serialize an optional value. If the value is itself an {@code Optional<S>},
* then mentioning {@code </none>} will yield a toplevel empty optional. So
@ -69,7 +68,7 @@ final class OptionalSyntax<T> extends XmlMapper<Optional<T>> {
}
@Override
public Optional<T> fromXml(Element element, XmlErrorReporter err) {
public Optional<T> fromXml(Element element, PmdXmlReporter err) {
if (EMPTY_NAME.equals(element.getTagName())) {
return Optional.empty();
} else {

View File

@ -12,13 +12,12 @@ import java.util.stream.Collectors;
import org.w3c.dom.Element;
import net.sourceforge.pmd.internal.util.xml.PmdXmlReporter;
import net.sourceforge.pmd.internal.util.xml.XmlErrorMessages;
import net.sourceforge.pmd.internal.util.xml.XmlUtil;
import net.sourceforge.pmd.properties.constraints.PropertyConstraint;
import net.sourceforge.pmd.properties.xml.XmlMapper.StableXmlMapper;
import com.github.oowekyala.ooxml.messages.XmlErrorReporter;
/**
* Serialize to and from a simple string. Examples:
*
@ -47,8 +46,8 @@ final class SeqSyntax<T, C extends Iterable<T>> extends StableXmlMapper<C> {
}
@Override
public C fromXml(Element element, XmlErrorReporter err) {
RuntimeException aggregateEx = err.error(element, XmlErrorMessages.ERR__LIST_CONSTRAINT_NOT_SATISFIED);
public C fromXml(Element element, PmdXmlReporter err) {
RuntimeException aggregateEx = err.at(element).error(XmlErrorMessages.ERR__LIST_CONSTRAINT_NOT_SATISFIED);
C result = XmlUtil.getElementChildren(element)
.map(child -> {

View File

@ -15,11 +15,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.w3c.dom.Element;
import net.sourceforge.pmd.internal.util.PredicateUtil;
import net.sourceforge.pmd.internal.util.xml.PmdXmlReporter;
import net.sourceforge.pmd.properties.constraints.PropertyConstraint;
import net.sourceforge.pmd.properties.xml.XmlMapper.StableXmlMapper;
import com.github.oowekyala.ooxml.messages.XmlErrorReporter;
/**
* Serialize to and from a simple string. Examples:
*
@ -77,11 +76,11 @@ class ValueSyntax<T> extends StableXmlMapper<T> {
}
@Override
public T fromXml(Element element, XmlErrorReporter err) {
public T fromXml(Element element, PmdXmlReporter err) {
try {
return fromString.apply(element.getTextContent());
} catch (IllegalArgumentException e) {
throw err.error(element, e);
throw err.at(element).error(e);
}
}

View File

@ -12,12 +12,13 @@ import java.util.Set;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import net.sourceforge.pmd.internal.util.xml.PmdXmlReporter;
import net.sourceforge.pmd.properties.PropertyFactory;
import net.sourceforge.pmd.properties.constraints.PropertyConstraint;
import net.sourceforge.pmd.util.log.MessageReporter;
import com.github.oowekyala.ooxml.messages.XmlErrorReporter;
import com.github.oowekyala.ooxml.messages.XmlException;
/**
@ -35,11 +36,11 @@ public abstract class XmlMapper<T> {
/**
* Extract the value from an XML element. If an error occurs, throws
* an exception with {@link XmlErrorReporter#error(Node, Throwable)}
* an {@link XmlException} with {@link MessageReporter#error(Throwable)}
* on the most specific node (the type of exception is unspecified).
* This will check property constraints if any.
*/
public abstract T fromXml(Element element, XmlErrorReporter err);
public abstract T fromXml(Element element, PmdXmlReporter err);
/** Write the value into the given XML element. */

View File

@ -1,4 +1,4 @@
/**
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
@ -27,6 +27,7 @@ import net.sourceforge.pmd.Rule;
import net.sourceforge.pmd.RulePriority;
import net.sourceforge.pmd.RuleSetReference;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.internal.util.xml.PmdXmlReporter;
import net.sourceforge.pmd.internal.util.xml.SchemaConstants;
import net.sourceforge.pmd.internal.util.xml.XmlErrorMessages;
import net.sourceforge.pmd.internal.util.xml.XmlUtil;
@ -34,6 +35,7 @@ import net.sourceforge.pmd.lang.Language;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.lang.LanguageVersion;
import net.sourceforge.pmd.lang.rule.RuleReference;
import net.sourceforge.pmd.lang.rule.internal.CommonPropertyDescriptors;
import net.sourceforge.pmd.properties.PropertyDescriptor;
import net.sourceforge.pmd.properties.PropertyTypeId;
import net.sourceforge.pmd.properties.PropertyTypeId.BuilderAndMapper;
@ -42,7 +44,6 @@ import net.sourceforge.pmd.util.ResourceLoader;
import net.sourceforge.pmd.util.StringUtil;
import com.github.oowekyala.ooxml.DomUtils;
import com.github.oowekyala.ooxml.messages.XmlErrorReporter;
import com.github.oowekyala.ooxml.messages.XmlException;
@ -102,7 +103,7 @@ public class RuleFactory {
*
* @return A rule reference to the referenced rule
*/
public RuleReference decorateRule(Rule referencedRule, RuleSetReference ruleSetReference, Element ruleElement, XmlErrorReporter err) {
public RuleReference decorateRule(Rule referencedRule, RuleSetReference ruleSetReference, Element ruleElement, PmdXmlReporter err) {
RuleReference ruleReference = new RuleReference(referencedRule, ruleSetReference);
DomUtils.getAttributeOpt(ruleElement, DEPRECATED).map(Boolean::parseBoolean).ifPresent(ruleReference::setDeprecated);
@ -125,8 +126,7 @@ public class RuleFactory {
setPropertyValues(ruleReference, node, err);
break;
default:
throw err.error(
node,
throw err.at(node).error(
XmlErrorMessages.ERR__UNEXPECTED_ELEMENT_IN,
"rule " + ruleReference.getName()
);
@ -148,14 +148,14 @@ public class RuleFactory {
*
* @throws IllegalArgumentException if the element doesn't describe a valid rule.
*/
public Rule buildRule(Element ruleElement, XmlErrorReporter err) {
public Rule buildRule(Element ruleElement, PmdXmlReporter err) {
Rule rule;
try {
String clazz = getNonBlankAttribute(ruleElement, err, CLASS);
rule = resourceLoader.loadRuleFromClassPath(clazz);
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
throw err.error(ruleElement.getAttributeNode(CLASS), e);
throw err.at(ruleElement.getAttributeNode(CLASS)).error(e);
}
rule.setName(getNonBlankAttribute(ruleElement, err, NAME));
@ -191,45 +191,45 @@ public class RuleFactory {
setPropertyValues(rule, node, err);
break;
default:
throw err.error(node,
XmlErrorMessages.ERR__UNEXPECTED_ELEMENT_IN,
"rule " + ruleElement.getAttribute(NAME));
throw err.at(node).error(
XmlErrorMessages.ERR__UNEXPECTED_ELEMENT_IN,
"rule " + ruleElement.getAttribute(NAME));
}
}
return rule;
}
private void checkVersionsAreOrdered(Element ruleElement, XmlErrorReporter err, Rule rule) {
private void checkVersionsAreOrdered(Element ruleElement, PmdXmlReporter err, Rule rule) {
if (rule.getMinimumLanguageVersion() != null && rule.getMaximumLanguageVersion() != null
&& rule.getMinimumLanguageVersion().compareTo(rule.getMaximumLanguageVersion()) > 0) {
throw err.fatal(
ruleElement.getAttributeNode(MINIMUM_LANGUAGE_VERSION),
XmlErrorMessages.ERR__INVALID_VERSION_RANGE,
rule.getMinimumLanguageVersion(),
rule.getMaximumLanguageVersion()
);
throw err.at(ruleElement.getAttributeNode(MINIMUM_LANGUAGE_VERSION))
.error(
XmlErrorMessages.ERR__INVALID_VERSION_RANGE,
rule.getMinimumLanguageVersion(),
rule.getMaximumLanguageVersion()
);
}
}
private @NonNull RulePriority parsePriority(XmlErrorReporter err, Element node, String trim) {
private @NonNull RulePriority parsePriority(PmdXmlReporter err, Element node, String trim) {
try {
int i = Integer.parseInt(trim.trim());
RulePriority rp = RulePriority.valueOfNullable(i);
if (rp == null) {
err.warn(node, XmlErrorMessages.WARN__INVALID_PRIORITY_VALUE, i);
err.at(node).warn(XmlErrorMessages.WARN__INVALID_PRIORITY_VALUE, i);
return RulePriority.MEDIUM;
} else {
return rp;
}
} catch (NumberFormatException e) {
err.warn(node, XmlErrorMessages.WARN__INVALID_PRIORITY_VALUE, trim);
err.at(node).warn(XmlErrorMessages.WARN__INVALID_PRIORITY_VALUE, trim);
return RulePriority.MEDIUM;
}
}
private LanguageVersion getLanguageVersion(Element ruleElement, XmlErrorReporter err, Language language, String attrName) {
private LanguageVersion getLanguageVersion(Element ruleElement, PmdXmlReporter err, Language language, String attrName) {
if (ruleElement.hasAttribute(attrName)) {
String attrValue = ruleElement.getAttribute(attrName);
LanguageVersion version = language.getVersion(attrValue);
@ -242,24 +242,24 @@ public class RuleFactory {
String message = supportedVersions.isEmpty()
? ERR__INVALID_LANG_VERSION_NO_NAMED_VERSION
: ERR__INVALID_LANG_VERSION;
throw err.fatal(
ruleElement.getAttributeNode(attrName),
message,
attrValue,
language.getTerseName(),
supportedVersions
);
throw err.at(ruleElement.getAttributeNode(attrName))
.error(
message,
attrValue,
language.getTerseName(),
supportedVersions
);
}
return version;
}
return null;
}
private void setLanguage(Element ruleElement, XmlErrorReporter err, Rule rule) {
private void setLanguage(Element ruleElement, PmdXmlReporter err, Rule rule) {
String langId = getNonBlankAttribute(ruleElement, err, LANGUAGE);
Language lang = LanguageRegistry.findLanguageByTerseName(langId);
if (lang == null) {
throw err.fatal(ruleElement.getAttributeNode(LANGUAGE), "Invalid language ''{0}'', possible values are {1}", langId, supportedLanguages());
throw err.at(ruleElement.getAttributeNode(LANGUAGE)).error("Invalid language ''{0}'', possible values are {1}", langId, supportedLanguages());
}
rule.setLanguage(lang);
}
@ -268,14 +268,14 @@ public class RuleFactory {
return LanguageRegistry.getLanguages().stream().map(Language::getTerseName).map(StringUtil::inSingleQuotes).collect(Collectors.joining(", "));
}
private @NonNull String getNonBlankAttribute(Element ruleElement, XmlErrorReporter err, String attrName) {
private @NonNull String getNonBlankAttribute(Element ruleElement, PmdXmlReporter err, String attrName) {
String clazz = ruleElement.getAttribute(attrName);
if (StringUtils.isBlank(clazz)) {
Attr attr = ruleElement.getAttributeNode(attrName);
if (attr == null) {
throw err.fatal(ruleElement, "Missing {0} attribute", attrName);
throw err.at(ruleElement).error("Missing {0} attribute", attrName);
} else {
throw err.fatal(attr, "This attribute may not be blank");
throw err.at(attr).error("This attribute may not be blank");
}
}
return clazz;
@ -285,11 +285,11 @@ public class RuleFactory {
* Parses the properties node and adds property definitions to the builder. Doesn't care for value overriding, that
* will be handled after the rule instantiation.
*
* @param rule Rule builder
* @param rule Rule builder
* @param propertiesNode Node to parse
* @param err Error reporter
*/
private void parsePropertiesForDefinitions(Rule rule, Element propertiesNode, @NonNull XmlErrorReporter err) {
private void parsePropertiesForDefinitions(Rule rule, Element propertiesNode, @NonNull PmdXmlReporter err) {
for (Element child : SchemaConstants.PROPERTY_ELT.getElementChildrenNamedReportOthers(propertiesNode, err)) {
if (isPropertyDefinition(child)) {
rule.definePropertyDescriptor(parsePropertyDefinition(child, err));
@ -303,21 +303,21 @@ public class RuleFactory {
* @param rule The rule
* @param propertiesElt The {@literal <properties>} element
*/
private void setPropertyValues(Rule rule, Element propertiesElt, XmlErrorReporter err) {
private void setPropertyValues(Rule rule, Element propertiesElt, PmdXmlReporter err) {
Set<String> overridden = new HashSet<>();
XmlException exception = null;
for (Element element : SchemaConstants.PROPERTY_ELT.getElementChildrenNamedReportOthers(propertiesElt, err)) {
String name = SchemaConstants.NAME.getAttributeOrThrow(element, err);
if (!overridden.add(name)) {
err.warn(element, IGNORED__DUPLICATE_PROPERTY_SETTER, name);
err.at(element).warn(IGNORED__DUPLICATE_PROPERTY_SETTER, name);
continue;
}
PropertyDescriptor<?> desc = rule.getPropertyDescriptor(name);
if (desc == null) {
// todo just warn and ignore
throw err.error(element, ERR__PROPERTY_DOES_NOT_EXIST, name, rule.getName());
throw err.at(element).error(ERR__PROPERTY_DOES_NOT_EXIST, name, rule.getName());
}
try {
setRulePropertyCapture(rule, desc, element, err);
@ -334,7 +334,7 @@ public class RuleFactory {
}
}
private <T> void setRulePropertyCapture(Rule rule, PropertyDescriptor<T> descriptor, Element propertyElt, XmlErrorReporter err) {
private <T> void setRulePropertyCapture(Rule rule, PropertyDescriptor<T> descriptor, Element propertyElt, PmdXmlReporter err) {
T value = parsePropertyValue(propertyElt, err, descriptor.xmlMapper());
rule.setProperty(descriptor, value);
}
@ -358,24 +358,24 @@ public class RuleFactory {
*
* @return The property descriptor
*/
private static PropertyDescriptor<?> parsePropertyDefinition(Element propertyElement, XmlErrorReporter err) {
private static PropertyDescriptor<?> parsePropertyDefinition(Element propertyElement, PmdXmlReporter err) {
String typeId = SchemaConstants.PROPERTY_TYPE.getAttributeOrThrow(propertyElement, err);
PropertyTypeId factory = PropertyTypeId.lookupMnemonic(typeId);
if (factory == null) {
throw err.fatal(
PROPERTY_TYPE.getAttributeNode(propertyElement),
"Unsupported property type ''{0}''",
typeId
);
throw err.at(PROPERTY_TYPE.getAttributeNode(propertyElement))
.error(
"Unsupported property type ''{0}''",
typeId
);
}
return propertyDefCapture(propertyElement, err, factory.getBuilderUtils());
}
private static <T> PropertyDescriptor<T> propertyDefCapture(Element propertyElement,
XmlErrorReporter err,
PmdXmlReporter err,
BuilderAndMapper<T> factory) {
// TODO support constraints like numeric range
@ -391,11 +391,11 @@ public class RuleFactory {
} catch (IllegalArgumentException e) {
// builder threw, rethrow with XML location
throw err.error(propertyElement, e.getMessage());
throw err.at(propertyElement).error(e);
}
}
private static <T> T parsePropertyValue(Element propertyElt, XmlErrorReporter err, XmlMapper<T> syntax) {
private static <T> T parsePropertyValue(Element propertyElt, PmdXmlReporter err, XmlMapper<T> syntax) {
@Nullable String defaultAttr = PROPERTY_VALUE.getAttributeOpt(propertyElt);
if (defaultAttr != null) {
Attr attrNode = PROPERTY_VALUE.getAttributeNode(propertyElt);
@ -409,10 +409,10 @@ public class RuleFactory {
try {
return syntax.fromString(defaultAttr);
} catch (IllegalArgumentException e) {
throw err.error(attrNode, e);
throw err.at(attrNode).error(e);
} catch (UnsupportedOperationException e) {
throw err.error(attrNode,
ERR__UNSUPPORTED_VALUE_ATTRIBUTE,
throw err.at(attrNode)
.error(ERR__UNSUPPORTED_VALUE_ATTRIBUTE,
String.join("\nor\n", syntax.getExamples()));
}

View File

@ -5,7 +5,9 @@
package net.sourceforge.pmd.util.log;
import java.text.MessageFormat;
import java.util.Objects;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.slf4j.event.Level;
import net.sourceforge.pmd.annotation.InternalApi;
@ -26,9 +28,16 @@ public interface MessageReporter {
boolean isLoggable(Level level);
void log(Level level, String message, Object... formatArgs);
default void log(Level level, String message, Object... formatArgs) {
logEx(level, message, formatArgs, null);
}
void logEx(Level level, String message, Object[] formatArgs, Throwable error);
void logEx(Level level, @Nullable String message, Object[] formatArgs, @Nullable Throwable error);
default RuntimeException newException(Level level, @Nullable Throwable cause, String message, Object... formatArgs) {
logEx(level, message, formatArgs, cause);
return new RuntimeException(MessageFormat.format(message, formatArgs), cause);
}
default void info(String message, Object... formatArgs) {
log(Level.INFO, message, formatArgs);
@ -46,8 +55,19 @@ public interface MessageReporter {
logEx(Level.WARN, message, formatArgs, error);
}
default void error(String message, Object... formatArgs) {
default RuntimeException error(String message, Object... formatArgs) {
log(Level.ERROR, message, formatArgs);
return newException(Level.ERROR, null, message, formatArgs);
}
default RuntimeException error(Throwable cause, String contextMessage, Object... formatArgs) {
logEx(Level.ERROR, contextMessage, formatArgs, Objects.requireNonNull(cause));
return newException(Level.ERROR, null, contextMessage, formatArgs);
}
default RuntimeException error(Throwable error) {
logEx(Level.ERROR, null, new Object[0], Objects.requireNonNull(error));
return newException(Level.ERROR, error, error.getMessage());
}
default void errorEx(String message, Throwable error) {

View File

@ -654,17 +654,17 @@ public class RuleSetFactoryTest {
@Test
public void testInvertedMinimumMaximumLanguageVersions() {
assertCannotParse(INVERTED_MINIMUM_MAXIMUM_LANGUAGE_VERSIONS);
verifyFoundAnErrorWithMessage(containing("versionRange"));
verifyFoundAnErrorWithMessage(containing("version range"));
}
private void verifyFoundAnErrorWithMessage(Predicate<String> messageTest) {
Mockito.verify(mockReporter, Mockito.times(1))
.log(Mockito.eq(Level.ERROR), Mockito.argThat(messageTest::test), Mockito.any());
.logEx(Mockito.eq(Level.ERROR), Mockito.argThat(messageTest::test), Mockito.any(), Mockito.any());
}
private void verifyFoundAWarningWithMessage(Predicate<String> messageTest) {
Mockito.verify(mockReporter, Mockito.times(1))
.log(Mockito.eq(Level.WARN), Mockito.argThat(messageTest::test), Mockito.any());
.logEx(Mockito.eq(Level.WARN), Mockito.argThat(messageTest::test), Mockito.any(), Mockito.any());
}
private static Predicate<String> containing(String part) {