# HG changeset patch # User Jaroslav Tulach # Date 1573545335 -3600 # Node ID 0e707eef1e4a02973f533e3cf1b39be532eb58d8 # Parent f11943a373a7c169e2e56d5933072a2d52a88ce5 Rewriting the Live DB example to Maven diff -r f11943a373a7 -r 0e707eef1e4a .hgignore --- a/.hgignore Mon Nov 11 13:17:34 2019 +0100 +++ b/.hgignore Tue Nov 12 08:55:35 2019 +0100 @@ -1,4 +1,5 @@ .*/build/.* +.*/target/.* .*/dist/.* .*/nbproject/private/.* .*.orig$ diff -r f11943a373a7 -r 0e707eef1e4a samples/livedb/build.xml --- a/samples/livedb/build.xml Mon Nov 11 13:17:34 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,111 +0,0 @@ - - - - - - - - - - - Builds, tests, and runs the project livedb. - - - - - - - - - - - - - - - - - - - - create table APP.AGE ( - NAME VARCHAR(30), - AGE NUMERIC(3) - ); - insert into APP.AGE values ('apidesign', 3); - - - none - - - - diff -r f11943a373a7 -r 0e707eef1e4a samples/livedb/livedb.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/livedb/livedb.xml Tue Nov 12 08:55:35 2019 +0100 @@ -0,0 +1,35 @@ + + + + + + + + + + + + + create table APP.AGE ( + NAME VARCHAR(30), + AGE NUMERIC(3) + ); + insert into APP.AGE values ('apidesign', 3); + + + none + + + + diff -r f11943a373a7 -r 0e707eef1e4a samples/livedb/nbproject/build-impl.xml --- a/samples/livedb/nbproject/build-impl.xml Mon Nov 11 13:17:34 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1770 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must set src.dir - Must set test.src.dir - Must set build.dir - Must set dist.dir - Must set build.classes.dir - Must set dist.javadoc.dir - Must set build.test.classes.dir - Must set build.test.results.dir - Must set build.classes.excludes - Must set dist.jar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must set javac.includes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - No tests executed. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must set JVM to use for profiling in profiler.info.jvm - Must set profiler agent JVM arguments in profiler.info.jvmargs.agent - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select some files in the IDE or set javac.includes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - To run this application from the command line without Ant, try: - - java -jar "${dist.jar.resolved}" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select one file in the IDE or set run.class - - - - Must select one file in the IDE or set run.class - - - - - - - - - - - - - - - - - - - - - - - Must select one file in the IDE or set debug.class - - - - - Must select one file in the IDE or set debug.class - - - - - Must set fix.includes - - - - - - - - - - This target only works when run from inside the NetBeans IDE. - - - - - - - - - Must select one file in the IDE or set profile.class - This target only works when run from inside the NetBeans IDE. - - - - - - - - - This target only works when run from inside the NetBeans IDE. - - - - - - - - - - - - - This target only works when run from inside the NetBeans IDE. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select one file in the IDE or set run.class - - - - - - Must select some files in the IDE or set test.includes - - - - - Must select one file in the IDE or set run.class - - - - - Must select one file in the IDE or set applet.url - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select some files in the IDE or set javac.includes - - - - - - - - - - - - - - - - - - - - - - - - Some tests failed; see details above. - - - - - - - - - Must select some files in the IDE or set test.includes - - - - Some tests failed; see details above. - - - - Must select some files in the IDE or set test.class - Must select some method in the IDE or set test.method - - - - Some tests failed; see details above. - - - - - Must select one file in the IDE or set test.class - - - - Must select one file in the IDE or set test.class - Must select some method in the IDE or set test.method - - - - - - - - - - - - - - Must select one file in the IDE or set applet.url - - - - - - - - - Must select one file in the IDE or set applet.url - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -r f11943a373a7 -r 0e707eef1e4a samples/livedb/nbproject/genfiles.properties --- a/samples/livedb/nbproject/genfiles.properties Mon Nov 11 13:17:34 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -build.xml.data.CRC32=acb473e7 -build.xml.script.CRC32=61ba5a6a -build.xml.stylesheet.CRC32=28e38971@1.39.0.45 -# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. -# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. -nbproject/build-impl.xml.data.CRC32=acb473e7 -nbproject/build-impl.xml.script.CRC32=186a778a -nbproject/build-impl.xml.stylesheet.CRC32=f89f7d21@1.93.0.48 diff -r f11943a373a7 -r 0e707eef1e4a samples/livedb/nbproject/project.properties --- a/samples/livedb/nbproject/project.properties Mon Nov 11 13:17:34 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -annotation.processing.enabled=true -annotation.processing.enabled.in.editor=true -annotation.processing.run.all.processors=true -annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output -application.title=livedb -application.vendor=jarda -build.classes.dir=${build.dir}/classes -build.classes.excludes=**/*.java,**/*.form -# This directory is removed when the project is cleaned: -build.dir=build -build.generated.dir=${build.dir}/generated -build.generated.sources.dir=${build.dir}/generated-sources -# Only compile against the classpath explicitly listed here: -build.sysclasspath=ignore -build.test.classes.dir=${build.dir}/test/classes -build.test.results.dir=${build.dir}/test/results -# Uncomment to specify the preferred debugger connection transport: -#debug.transport=dt_socket -debug.classpath=\ - ${run.classpath} -debug.modulepath=\ - ${run.modulepath} -debug.test.classpath=\ - ${run.test.classpath} -debug.test.modulepath=\ - ${run.test.modulepath} -# This directory is removed when the project is cleaned: -dist.dir=dist -dist.jar=${dist.dir}/livedb.jar -dist.javadoc.dir=${dist.dir}/javadoc -endorsed.classpath= -excludes= -file.reference.derby.jar=../libs/dist/derby.jar -file.reference.junit-4.4.jar=../libs/dist/junit-4.4.jar -file.reference.org-openide-util-lookup.jar=../libs/dist/org-openide-util-lookup.jar -includes=** -jar.compress=false -javac.classpath=\ - ${file.reference.org-openide-util-lookup.jar} -# Space-separated list of extra javac options -javac.compilerargs= -javac.deprecation=false -javac.modulepath= -javac.processormodulepath= -javac.processorpath=\ - ${javac.classpath} -javac.source=1.6 -javac.target=1.6 -javac.test.classpath=\ - ${javac.classpath}:\ - ${build.classes.dir}:\ - ${file.reference.derby.jar}:\ - ${file.reference.junit-4.4.jar} -javac.test.modulepath=\ - ${javac.modulepath} -javac.test.processorpath=\ - ${javac.test.classpath} -javadoc.additionalparam= -javadoc.author=false -javadoc.encoding=${source.encoding} -javadoc.noindex=false -javadoc.nonavbar=false -javadoc.notree=false -javadoc.private=false -javadoc.splitindex=true -javadoc.use=true -javadoc.version=false -javadoc.windowtitle= -meta.inf.dir=${src.dir}/META-INF -platform.active=default_platform -run.classpath=\ - ${javac.classpath}:\ - ${build.classes.dir} -# Space-separated list of JVM arguments used when running the project -# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value -# or test-sys-prop.name=value to set system properties for unit tests): -run.jvmargs= -run.modulepath=\ - ${javac.modulepath} -run.test.classpath=\ - ${javac.test.classpath}:\ - ${build.test.classes.dir} -run.test.modulepath=\ - ${javac.test.modulepath} -source.encoding=UTF-8 -src.dir=src -test.src.dir=test diff -r f11943a373a7 -r 0e707eef1e4a samples/livedb/nbproject/project.xml --- a/samples/livedb/nbproject/project.xml Mon Nov 11 13:17:34 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ - - - org.netbeans.modules.java.j2seproject - - - livedb - - - - - - - - - diff -r f11943a373a7 -r 0e707eef1e4a samples/livedb/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/livedb/pom.xml Tue Nov 12 08:55:35 2019 +0100 @@ -0,0 +1,82 @@ + + + 4.0.0 + + org.apidesign.samples + livedb + 1.0-SNAPSHOT + jar + + LiveDB + + API Design + http://apidesign.org + + + UTF-8 + 1.8 + 1.8 + none + + + + + + maven-antrun-plugin + 1.8 + + + validate + + + + + + + + + + run + + + + + + + + + + org.netbeans.api + org-openide-util-lookup + RELEASE112 + jar + provided + + + org.apache.derby + derby + 10.15.1.3 + jar + + + org.apache.derby + derbyclient + 10.15.1.3 + jar + + + org.apache.derby + derbyshared + 10.15.1.3 + jar + + + junit + junit + 4.12 + test + jar + + + diff -r f11943a373a7 -r 0e707eef1e4a samples/livedb/src/main/java/org/apidesign/livedb/LiveDB.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/livedb/src/main/java/org/apidesign/livedb/LiveDB.java Tue Nov 12 08:55:35 2019 +0100 @@ -0,0 +1,22 @@ +package org.apidesign.livedb; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author Jaroslav Tulach + */ +// BEGIN: livedb.connection.annotation +@Target(ElementType.PACKAGE) +@Retention(RetentionPolicy.SOURCE) +public @interface LiveDB { + String url(); + String user(); + String password(); + String query(); + String classname(); +} +// END: livedb.connection.annotation diff -r f11943a373a7 -r 0e707eef1e4a samples/livedb/src/main/java/org/apidesign/livedb/impl/LiveDBProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/livedb/src/main/java/org/apidesign/livedb/impl/LiveDBProcessor.java Tue Nov 12 08:55:35 2019 +0100 @@ -0,0 +1,228 @@ +package org.apidesign.livedb.impl; + +import java.io.IOException; +import java.io.Writer; +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.Driver; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.ServiceLoader; +import java.util.Set; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.Completion; +import javax.annotation.processing.Completions; +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.SourceVersion; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; +import org.apidesign.livedb.LiveDB; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * @author Jaroslav Tulach + */ +// BEGIN: livedb.processor +@SupportedAnnotationTypes("org.apidesign.livedb.LiveDB") +@SupportedSourceVersion(SourceVersion.RELEASE_6) +@ServiceProvider(service=Processor.class) +public final class LiveDBProcessor extends AbstractProcessor { + @Override + public boolean process( + Set annotations, RoundEnvironment roundEnv + ) { + final Filer filer = processingEnv.getFiler(); + for (Element e : roundEnv.getElementsAnnotatedWith(LiveDB.class)) { + LiveDB db = e.getAnnotation(LiveDB.class); + PackageElement pe = (PackageElement)e; + String clsName = pe.getQualifiedName() + "." + db.classname(); + try { + JavaFileObject src = filer.createSourceFile(clsName, pe); + Writer w = src.openWriter(); + Connection c = getConnection( + db.url(), db.user(), db.password() + ); + CallableStatement s = c.prepareCall(db.query()); + ResultSet rs = s.executeQuery(); + ResultSetMetaData md = rs.getMetaData(); + generateClassHeader(w, pe, db); + w.append("class " + db.classname() + " {\n"); + for (int i = 1; i <= md.getColumnCount(); i++) { + generateField(w, md, i); + } + generateConstructor(w, db, md); + generateQueryMethod(w, db, md); + w.append("}"); + w.close(); + } catch (IOException | SQLException ex) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, ex.getMessage(), e); + } + } + return true; + } +// FINISH: livedb.processor + + private void generateQueryMethod(Writer w, LiveDB db, ResultSetMetaData md) throws SQLException, IOException { + w.append(" public static List<" + db.classname() + "> ") + .append("query() throws SQLException {\n"); + w.append(" Connection c = DriverManager.getConnection(\"") + .append(db.url()).append("\", \"") + .append(db.user()).append("\", \"") + .append(db.password()).append("\");\n"); + w.append(" List<").append(db.classname()) + .append("> res = new ArrayList<") + .append(db.classname()).append(">();\n"); + w.append(" CallableStatement s = c.prepareCall(\"") + .append(db.query()).append("\");\n"); + w.append(" ResultSet rs = s.executeQuery();\n"); + w.append(" ResultSetMetaData md = rs.getMetaData();\n"); + w.append(" while (rs.next()) {\n"); + w.append(" res.add(new " + db.classname() + "(\n"); + for (int i = 1; i <= md.getColumnCount(); i++) { + w.append(" (") + .append(md.getColumnClassName(i)) + .append(")rs.getObject(" + i).append(")"); + if (i < md.getColumnCount()) { + w.append(",\n"); + } else { + w.append("\n"); + } + } + w.append(" ));\n"); + w.append(" };\n"); + w.append(" return res;\n"); + w.append(" }"); + } + + private void generateConstructor(Writer w, LiveDB db, ResultSetMetaData md) throws SQLException, IOException { + w.append(" private " + db.classname() + "(\n"); + for (int i = 1; i <= md.getColumnCount(); i++) { + w.append(" ").append(md.getColumnClassName(i)) + .append(" ").append(md.getColumnName(i)); + if (i < md.getColumnCount()) { + w.append(",\n"); + } else { + w.append("\n"); + } + } + w.append(" ) {\n"); + for (int i = 1; i <= md.getColumnCount(); i++) { + w.append(" this.") + .append(md.getColumnName(i)) + .append(" = ") + .append(md.getColumnName(i)) + .append(";\n"); + } + w.append(" }\n"); + } + + private void generateField(Writer w, ResultSetMetaData md, int i) throws IOException, SQLException { + w.append(" public final ") + .append(md.getColumnClassName(i)) + .append(" ") + .append(md.getColumnName(i)) + .append(";\n"); + } + + private void generateClassHeader(Writer w, PackageElement pe, LiveDB db) throws IOException { + w.append("package " + pe.getQualifiedName() + ";\n"); + w.append("import java.util.List;\n"); + w.append("import java.util.ArrayList;\n"); + w.append("import java.sql.*;\n"); + } + private static Connection getConnection(String url, String user, String password) + throws SQLException { + final ClassLoader cl = LiveDBProcessor.class.getClassLoader(); + for (Driver d : ServiceLoader.load(Driver.class, cl)) { +// System.out.println("looked up: " + d); + if (d.acceptsURL(url)) { + //System.out.println("accepts: " + d); + Properties p = new Properties(); + p.put("user", user); + p.put("password", password); + return d.connect(url, p); + } + } + throw new SQLException("No driver found for " + url); + } + + + + // BEGIN: livedb.completions + @Override + public Iterable getCompletions( + Element element, AnnotationMirror annotation, + ExecutableElement member, String userText + ) { + if (!"query".equals(member.getSimpleName().toString())) { + return Collections.emptyList(); + } + if (userText == null || userText.length() <= 1) { + return Collections.singleton(Completions.of("\"SELECT ")); + } + if (userText.toUpperCase().matches(".*FROM *")) { + String user = extractValue(annotation, "user"); + String password = extractValue(annotation, "password"); + String url = extractValue(annotation, "url"); + if (user == null || password == null || url == null) { + return Collections.emptyList(); + } + try { + List arr = new ArrayList(); + Connection c = getConnection(url, user, password); + DatabaseMetaData meta = c.getMetaData(); + ResultSet res = meta.getTables(null, null, "%", null); + boolean ok = res.first(); + while (ok) { + String txt = userText + res.getString("TABLE_NAME"); + arr.add(Completions.of(txt)); + ok = res.next(); + } + return arr; + } catch (SQLException ex) { + throw new IllegalStateException(ex); + } + } + return Collections.emptyList(); + } + // END: livedb.completions + + private static String extractValue(AnnotationMirror am, String param) { + AnnotationValue av = null; + for (Entry entry : am.getElementValues().entrySet()) { + if (entry.getKey().toString().equals(param + "()")) { + av = entry.getValue(); + break; + } + } + if (av == null) { + return null; + } + String s = av.toString(); + if (s.startsWith("\"")) { + s = s.substring(1); + } + if (s.endsWith("\"")) { + s = s.substring(0, s.length() - 1); + } + return s; + } +} diff -r f11943a373a7 -r 0e707eef1e4a samples/livedb/src/org/apidesign/livedb/LiveDB.java --- a/samples/livedb/src/org/apidesign/livedb/LiveDB.java Mon Nov 11 13:17:34 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -package org.apidesign.livedb; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * - * @author Jaroslav Tulach - */ -// BEGIN: livedb.connection.annotation -@Target(ElementType.PACKAGE) -@Retention(RetentionPolicy.SOURCE) -public @interface LiveDB { - String url(); - String user(); - String password(); - String query(); - String classname(); -} -// END: livedb.connection.annotation diff -r f11943a373a7 -r 0e707eef1e4a samples/livedb/src/org/apidesign/livedb/impl/LiveDBProcessor.java --- a/samples/livedb/src/org/apidesign/livedb/impl/LiveDBProcessor.java Mon Nov 11 13:17:34 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,229 +0,0 @@ -package org.apidesign.livedb.impl; - -import java.io.IOException; -import java.io.Writer; -import java.sql.CallableStatement; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.Driver; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map.Entry; -import java.util.Properties; -import java.util.ServiceLoader; -import java.util.Set; -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.Completion; -import javax.annotation.processing.Completions; -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.SourceVersion; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.Element; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeElement; -import javax.tools.JavaFileObject; -import org.apidesign.livedb.LiveDB; -import org.openide.util.lookup.ServiceProvider; - -/** - * - * @author Jaroslav Tulach - */ -// BEGIN: livedb.processor -@SupportedAnnotationTypes("org.apidesign.livedb.LiveDB") -@SupportedSourceVersion(SourceVersion.RELEASE_6) -@ServiceProvider(service=Processor.class) -public final class LiveDBProcessor extends AbstractProcessor { - @Override - public boolean process( - Set annotations, RoundEnvironment roundEnv - ) { - final Filer filer = processingEnv.getFiler(); - for (Element e : roundEnv.getElementsAnnotatedWith(LiveDB.class)) { - LiveDB db = e.getAnnotation(LiveDB.class); - PackageElement pe = (PackageElement)e; - String clsName = pe.getQualifiedName() + "." + db.classname(); - try { - JavaFileObject src = filer.createSourceFile(clsName, pe); - Writer w = src.openWriter(); - Connection c = getConnection( - db.url(), db.user(), db.password() - ); - CallableStatement s = c.prepareCall(db.query()); - ResultSet rs = s.executeQuery(); - ResultSetMetaData md = rs.getMetaData(); - generateClassHeader(w, pe, db); - w.append("class " + db.classname() + " {\n"); - for (int i = 1; i <= md.getColumnCount(); i++) { - generateField(w, md, i); - } - generateConstructor(w, db, md); - generateQueryMethod(w, db, md); - w.append("}"); - w.close(); - } catch (IOException ex) { - throw new IllegalStateException(ex); - } catch (SQLException ex) { - throw new IllegalStateException(ex); - } - } - return true; - } -// FINISH: livedb.processor - - private void generateQueryMethod(Writer w, LiveDB db, ResultSetMetaData md) throws SQLException, IOException { - w.append(" public static List<" + db.classname() + "> ") - .append("query() throws SQLException {\n"); - w.append(" Connection c = DriverManager.getConnection(\"") - .append(db.url()).append("\", \"") - .append(db.user()).append("\", \"") - .append(db.password()).append("\");\n"); - w.append(" List<").append(db.classname()) - .append("> res = new ArrayList<") - .append(db.classname()).append(">();\n"); - w.append(" CallableStatement s = c.prepareCall(\"") - .append(db.query()).append("\");\n"); - w.append(" ResultSet rs = s.executeQuery();\n"); - w.append(" ResultSetMetaData md = rs.getMetaData();\n"); - w.append(" while (rs.next()) {\n"); - w.append(" res.add(new " + db.classname() + "(\n"); - for (int i = 1; i <= md.getColumnCount(); i++) { - w.append(" (") - .append(md.getColumnClassName(i)) - .append(")rs.getObject(" + i).append(")"); - if (i < md.getColumnCount()) { - w.append(",\n"); - } else { - w.append("\n"); - } - } - w.append(" ));\n"); - w.append(" };\n"); - w.append(" return res;\n"); - w.append(" }"); - } - - private void generateConstructor(Writer w, LiveDB db, ResultSetMetaData md) throws SQLException, IOException { - w.append(" private " + db.classname() + "(\n"); - for (int i = 1; i <= md.getColumnCount(); i++) { - w.append(" ").append(md.getColumnClassName(i)) - .append(" ").append(md.getColumnName(i)); - if (i < md.getColumnCount()) { - w.append(",\n"); - } else { - w.append("\n"); - } - } - w.append(" ) {\n"); - for (int i = 1; i <= md.getColumnCount(); i++) { - w.append(" this.") - .append(md.getColumnName(i)) - .append(" = ") - .append(md.getColumnName(i)) - .append(";\n"); - } - w.append(" }\n"); - } - - private void generateField(Writer w, ResultSetMetaData md, int i) throws IOException, SQLException { - w.append(" public final ") - .append(md.getColumnClassName(i)) - .append(" ") - .append(md.getColumnName(i)) - .append(";\n"); - } - - private void generateClassHeader(Writer w, PackageElement pe, LiveDB db) throws IOException { - w.append("package " + pe.getQualifiedName() + ";\n"); - w.append("import java.util.List;\n"); - w.append("import java.util.ArrayList;\n"); - w.append("import java.sql.*;\n"); - } - private static Connection getConnection(String url, String user, String password) - throws SQLException { - final ClassLoader cl = LiveDBProcessor.class.getClassLoader(); - for (Driver d : ServiceLoader.load(Driver.class, cl)) { -// System.out.println("looked up: " + d); - if (d.acceptsURL(url)) { - //System.out.println("accepts: " + d); - Properties p = new Properties(); - p.put("user", user); - p.put("password", password); - return d.connect(url, p); - } - } - throw new SQLException("No driver found for " + url); - } - - - - // BEGIN: livedb.completions - @Override - public Iterable getCompletions( - Element element, AnnotationMirror annotation, - ExecutableElement member, String userText - ) { - if (!"query".equals(member.getSimpleName().toString())) { - return Collections.emptyList(); - } - if (userText == null || userText.length() <= 1) { - return Collections.singleton(Completions.of("\"SELECT ")); - } - if (userText.toUpperCase().matches(".*FROM *")) { - String user = extractValue(annotation, "user"); - String password = extractValue(annotation, "password"); - String url = extractValue(annotation, "url"); - if (user == null || password == null || url == null) { - return Collections.emptyList(); - } - try { - List arr = new ArrayList(); - Connection c = getConnection(url, user, password); - DatabaseMetaData meta = c.getMetaData(); - ResultSet res = meta.getTables(null, null, "%", null); - boolean ok = res.first(); - while (ok) { - String txt = userText + res.getString("TABLE_NAME"); - arr.add(Completions.of(txt)); - ok = res.next(); - } - return arr; - } catch (SQLException ex) { - throw new IllegalStateException(ex); - } - } - return Collections.emptyList(); - } - // END: livedb.completions - - private static String extractValue(AnnotationMirror am, String param) { - AnnotationValue av = null; - for (Entry entry : am.getElementValues().entrySet()) { - if (entry.getKey().toString().equals(param + "()")) { - av = entry.getValue(); - break; - } - } - if (av == null) { - return null; - } - String s = av.toString(); - if (s.startsWith("\"")) { - s = s.substring(1); - } - if (s.endsWith("\"")) { - s = s.substring(0, s.length() - 1); - } - return s; - } -} diff -r f11943a373a7 -r 0e707eef1e4a samples/livedb/src/test/java/org/apidesign/livedb/example/LiveDBTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/livedb/src/test/java/org/apidesign/livedb/example/LiveDBTest.java Tue Nov 12 08:55:35 2019 +0100 @@ -0,0 +1,28 @@ +package org.apidesign.livedb.example; + +import java.sql.SQLException; +import java.util.List; +import static junit.framework.TestCase.assertEquals; +import org.junit.Test; + +/** + * + * @author Jaroslav Tulach + */ +public class LiveDBTest { + + public LiveDBTest() { + } + + @Test + public void testSomeMethod() throws SQLException { + // BEGIN: livedb.test + List ages = Age.query(); + assertEquals("One record", 1, ages.size()); + Age age = ages.get(0); + assertEquals("name is apidesign", "apidesign", age.NAME); + assertEquals("it is three years old", 3, age.AGE.intValue()); + // END: livedb.test + } + +} diff -r f11943a373a7 -r 0e707eef1e4a samples/livedb/src/test/java/org/apidesign/livedb/example/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/livedb/src/test/java/org/apidesign/livedb/example/package-info.java Tue Nov 12 08:55:35 2019 +0100 @@ -0,0 +1,11 @@ + +// BEGIN: livedb.connect +@LiveDB( + classname="Age", password="j1", user="j1", + query="select * from APP.AGE", + url="jdbc:derby:classpath:db" +) +package org.apidesign.livedb.example; +// END: livedb.connect + +import org.apidesign.livedb.LiveDB; diff -r f11943a373a7 -r 0e707eef1e4a samples/livedb/test/org/apidesign/livedb/example/LiveDBTest.java --- a/samples/livedb/test/org/apidesign/livedb/example/LiveDBTest.java Mon Nov 11 13:17:34 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -package org.apidesign.livedb.example; - -import java.sql.SQLException; -import java.util.List; -import junit.framework.TestCase; - -/** - * - * @author Jaroslav Tulach - */ -public class LiveDBTest extends TestCase { - - public LiveDBTest(String testName) { - super(testName); - } - - public void testSomeMethod() throws SQLException { - // BEGIN: livedb.test - List ages = Age.query(); - assertEquals("One record", 1, ages.size()); - Age age = ages.get(0); - assertEquals("name is apidesign", "apidesign", age.NAME); - assertEquals("it is three years old", 3, age.AGE.intValue()); - // END: livedb.test - } - -} diff -r f11943a373a7 -r 0e707eef1e4a samples/livedb/test/org/apidesign/livedb/example/package-info.java --- a/samples/livedb/test/org/apidesign/livedb/example/package-info.java Mon Nov 11 13:17:34 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ - -// BEGIN: livedb.connect -@LiveDB( - classname="Age", password="j1", user="j1", - query="select * from APP.AGE", - url="jdbc:derby:classpath:db" -) -package org.apidesign.livedb.example; -// END: livedb.connect - -import org.apidesign.livedb.LiveDB;