hm.binkley.xml.XMLFuzzyProcessor Maven / Gradle / Ivy
/*
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to .
*/
package hm.binkley.xml;
import freemarker.template.Configuration;
import freemarker.template.TemplateException;
import hm.binkley.xml.XMLFuzzy.Field;
import org.intellij.lang.annotations.Language;
import org.kohsuke.MetaInfServices;
import org.w3c.dom.Node;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.NotThreadSafe;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static java.lang.String.format;
import static java.lang.reflect.Modifier.isStatic;
import static java.util.Arrays.asList;
import static javax.lang.model.SourceVersion.RELEASE_8;
import static javax.lang.model.type.TypeKind.VOID;
import static javax.tools.Diagnostic.Kind.ERROR;
import static javax.tools.StandardLocation.CLASS_PATH;
/**
* {@code FuzzyProcessor} needs documentation.
*
* @author B. K. Oxley (binkley)
* @todo Needs documentation.
* @todo Think through use of FreeMarker - logging dependencies, runtime dependency
* @todo Support inner interfaces
* @todo How to map evaluate parameters onto xpath resolver map?
*/
@MetaInfServices(Processor.class)
@SupportedAnnotationTypes({"hm.binkley.xml.XMLFuzzy", "hm.binkley.xml.XMLFuzzy.Field"})
@SupportedSourceVersion(RELEASE_8)
@NotThreadSafe
public class XMLFuzzyProcessor
extends AbstractProcessor {
private static final XPathFactory xpathFactory = XPathFactory.newInstance();
private static final Map expressions = new HashMap<>();
/**
* Evaluate an XPath expression against node using a common, shared cache
* for compiled expressions.
*
* @param node the document node, never missing
* @param expression the xpath expression, never missing
*
* @return the evaluation result
*
* @throws XPathExpressionException
* @todo Thread safety
*/
@Nonnull
public static String evaluate(@Nonnull final Node node,
@Nonnull @Language("XPath") final String expression)
throws XPathExpressionException {
try {
return expressions.computeIfAbsent(expression, expr -> {
try {
return xpathFactory.newXPath().compile(expr);
} catch (final XPathExpressionException e) {
throw new Passing(e);
}
}).evaluate(node).intern();
} catch (final Passing passing) {
throw (XPathExpressionException) passing.getCause();
}
}
private static final class Passing
extends RuntimeException {
private Passing(final XPathExpressionException real) {
super(real);
}
}
@Override
public boolean process(final Set extends TypeElement> annotations,
final RoundEnvironment roundEnv) {
final Filer filer = processingEnv.getFiler();
final Configuration configuration = new Configuration();
try {
configuration.setDirectoryForTemplateLoading(new File(
filer.getResource(CLASS_PATH, getClass().getPackage().getName(), "fuzzy.ftl")
.toUri()).getParentFile());
} catch (final IOException e) {
processingEnv.getMessager().printMessage(ERROR, e.toString());
return false;
}
for (final Element element : roundEnv.getElementsAnnotatedWith(XMLFuzzy.class)) {
try {
final PackageElement packaj = processingEnv.getElementUtils().getPackageOf(element);
final Name simpleName = element.getSimpleName();
try (final Writer out = filer
.createSourceFile(packaj + "." + simpleName + "Factory", element)
.openWriter()) {
final Map model = new HashMap<>();
model.put("generator", XMLFuzzyProcessor.class.getName());
model.put("date", Instant.now());
model.put("package", packaj);
model.put("simpleName", simpleName);
//noinspection unchecked
final Set methodElements = (Set) roundEnv
.getElementsAnnotatedWith(Field.class);
final List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy