Skip to content

Commit

Permalink
adds an abstract class for resources generation in AP
Browse files Browse the repository at this point in the history
In factory annotation processor a class was used to generate the
machine service file.
This process use from now on the abstract class ResourceDeclaration
defined in RestxAbstractProcessor.

Like this other processors having the same need, might also use the
ResourceDeclaration class.
  • Loading branch information
a-peyrard committed Mar 15, 2015
1 parent e22c813 commit ad583cc
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 83 deletions.
Expand Up @@ -15,9 +15,15 @@
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Set;
Expand Down Expand Up @@ -110,4 +116,119 @@ protected void generateJavaClass(String className, Template mustache, ImmutableM
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}

/**
* Abstract class to manage resource file generation, it permits to read existing content using the
* {@link #processing()} method, which will call the abstract {@link #readContent(java.io.Reader)} method.
* And the method {@link #generate()} need to be called once we want to generate the resource, during this process
* the {@link #writeContent(java.io.Writer)} method will be called.
*/
protected abstract class ResourceDeclaration {
private final String targetFilePath;
private FileObject fileObject;

/**
* @param targetFilePath path of the resource to write
*/
protected ResourceDeclaration(String targetFilePath) {
this.targetFilePath = targetFilePath;
}

/**
* @return true if the resource need to be generated (for example, it permits to skip empty contents)
*/
protected abstract boolean requireGeneration();

/**
* called once the file has been written
*/
protected abstract void clearContent();

/**
* Writes the resource content.
*
* @param writer the writer to use
* @throws IOException if an I/O error occurs
*/
protected abstract void writeContent(Writer writer) throws IOException;

/**
* Reads the resource content.
*
* @param reader the reader to use
* @throws IOException if an I/O error occurs
*/
protected abstract void readContent(Reader reader) throws IOException;

public void generate() throws IOException {
if (!requireGeneration()) {
return;
}

writeResourceFile(targetFilePath);

clearContent();

fileObject = null;
}

public void processing() throws IOException {
readExistingResourceIfExists(targetFilePath);
}

private void writeResourceFile(String targetFile) throws IOException {
if (fileObject != null
&& fileObject.getClass().getSimpleName().equals("EclipseFileObject")
) {
// eclipse does not allow to do a createResource for a fileobject already obtained via getResource
// but the file object can be used for writing, so it's ok to reuse it in this case

// see source code at:
// https://github.com/eclipse/eclipse.jdt.core/blob/master/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java
// https://github.com/eclipse/eclipse.jdt.core/blob/master/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileObject.java
} else {
try {
fileObject = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", targetFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
try (Writer writer = fileObject.openWriter()) {
writeContent(writer);
}
}

private void readExistingResourceIfExists(String targetFile) throws IOException {
try {
if (fileObject == null) {
fileObject = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", targetFile);
}
try (Reader r = fileObject.openReader(true)) {
readContent(r);
}
} catch (FileNotFoundException ex) {
/*
This is a very strange behaviour of javac during incremantal compilation (at least experienced
with Intellij make process): a FileNotFoundException is raised while the file actually exist.
"Fortunately" the exception message is the path of the file, so we can try to load it using
plain java.io
*/
try {
File file = new File(ex.getMessage());
if (file.exists()) {
try (Reader r = new FileReader(file)) {
readContent(r);
} catch (IOException e) {
// ignore
}
}
} catch (Exception e) {
// ignore
}
} catch (IOException | IllegalArgumentException ex) {
// ignore
}
}
}
}
Expand Up @@ -17,8 +17,6 @@
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.MirroredTypeException;
import javax.lang.model.type.TypeMirror;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import java.io.*;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -727,91 +725,37 @@ private static class ConditionalProviderMethod {
}


private class ServicesDeclaration {
private class ServicesDeclaration extends ResourceDeclaration {
private final Set<String> declaredServices = Sets.newHashSet();
private final String targetFile;
private FileObject fileObject;

private ServicesDeclaration(String targetFile) {
this.targetFile = "META-INF/services/" + targetFile;
}

void declareService(String service) {
super("META-INF/services/" + targetFile);
}

@Override
protected boolean requireGeneration() {
return declaredServices.size() > 0;
}

@Override
protected void clearContent() {
declaredServices.clear();
}

@Override
protected void writeContent(Writer writer) throws IOException {
for (String declaredService : Ordering.natural().sortedCopy(declaredServices)) {
writer.write(declaredService + "\n");
}
}

@Override
protected void readContent(Reader reader) throws IOException {
declaredServices.addAll(CharStreams.readLines(reader));
}

void declareService(String service) {
declaredServices.add(service);
}

void generate() throws IOException {
if (declaredServices.isEmpty()) {
return;
}

writeServicesFile(targetFile);

declaredServices.clear();

fileObject = null;
}


public void processing() throws IOException {
readExistingServicesIfExists(targetFile);
}

private void writeServicesFile(String targetFile) throws IOException {
if (fileObject != null
&& fileObject.getClass().getSimpleName().equals("EclipseFileObject")
) {
// eclipse does not allow to do a createResource for a fileobject already obtained via getResource
// but the file object can be used for writing, so it's ok to reuse it in this case

// see source code at:
// https://github.com/eclipse/eclipse.jdt.core/blob/master/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java
// https://github.com/eclipse/eclipse.jdt.core/blob/master/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileObject.java
} else {
try {
fileObject = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", targetFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
try (Writer writer = fileObject.openWriter()) {
for (String declaredService : Ordering.natural().sortedCopy(declaredServices)) {
writer.write(declaredService + "\n");
}
}
}

private void readExistingServicesIfExists(String targetFile) throws IOException {
try {
if (fileObject == null) {
fileObject = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", targetFile);
}
try (Reader r = fileObject.openReader(true)) {
declaredServices.addAll(CharStreams.readLines(r));
}
} catch (FileNotFoundException ex) {
/*
This is a very strange behaviour of javac during incremantal compilation (at least experienced
with Intellij make process): a FileNotFoundException is raised while the file actually exist.
"Fortunately" the exception message is the path of the file, so we can try to load it using
plain java.io
*/
try {
File file = new File(ex.getMessage());
if (file.exists()) {
try (Reader r = new FileReader(file)) {
declaredServices.addAll(CharStreams.readLines(r));
} catch (IOException e) {
// ignore
}
}
} catch (Exception e) {
// ignore
}
} catch (IOException | IllegalArgumentException ex) {
// ignore
}
}
}
}

0 comments on commit ad583cc

Please sign in to comment.