From a603d745fb957f306bee2c4c30ef4d1cd7d2048d Mon Sep 17 00:00:00 2001 From: lukaseder Date: Sun, 15 May 2016 16:15:48 +0200 Subject: [PATCH] [#5245] Improved @Require behaviour and spec --- .../org/jooq/checker/AbstractChecker.java | 4 + .../org/jooq/checker/SQLDialectChecker.java | 49 +++++++++--- .../jOOQ-checker-framework-example/pom.xml | 2 +- .../checker/SQLDialectCheckerTests.java | 78 +++++++++++++++---- jOOQ/src/main/java/org/jooq/Allow.java | 4 +- jOOQ/src/main/java/org/jooq/Require.java | 4 +- 6 files changed, 112 insertions(+), 29 deletions(-) diff --git a/jOOQ-checker/src/main/java/org/jooq/checker/AbstractChecker.java b/jOOQ-checker/src/main/java/org/jooq/checker/AbstractChecker.java index fa46c89c01..a05a5aa798 100644 --- a/jOOQ-checker/src/main/java/org/jooq/checker/AbstractChecker.java +++ b/jOOQ-checker/src/main/java/org/jooq/checker/AbstractChecker.java @@ -58,6 +58,10 @@ abstract class AbstractChecker extends SourceChecker { getChecker().report(Result.failure(message, node), node); } + void warn(Object node, String message) { + getChecker().report(Result.warning(message, node), node); + } + void print(Printer printer) { try (PrintWriter writer = new PrintWriter(new FileWriter("error.txt"))){ writer.println("This is probably a bug in jOOQ-checker."); diff --git a/jOOQ-checker/src/main/java/org/jooq/checker/SQLDialectChecker.java b/jOOQ-checker/src/main/java/org/jooq/checker/SQLDialectChecker.java index b0fd4cbbe9..0c9a6b6bdb 100644 --- a/jOOQ-checker/src/main/java/org/jooq/checker/SQLDialectChecker.java +++ b/jOOQ-checker/src/main/java/org/jooq/checker/SQLDialectChecker.java @@ -86,18 +86,25 @@ public class SQLDialectChecker extends AbstractChecker { EnumSet supported = EnumSet.copyOf(asList(support.value())); EnumSet allowed = EnumSet.noneOf(SQLDialect.class); - EnumSet required = EnumSet.allOf(SQLDialect.class); - EnumSet x; + EnumSet required = EnumSet.noneOf(SQLDialect.class); + boolean evaluateRequire = true; while (enclosing != null) { Allow allow = enclosing.getAnnotation(Allow.class); - Require require = enclosing.getAnnotation(Require.class); if (allow != null) allowed.addAll(asList(allow.value())); - if (require != null) - required.retainAll(asList(require.value())); + if (evaluateRequire) { + Require require = enclosing.getAnnotation(Require.class); + + if (require != null) { + evaluateRequire = false; + + required.clear(); + required.addAll(asList(require.value())); + } + } enclosing = enclosing.getEnclosingElement(); } @@ -108,13 +115,33 @@ public class SQLDialectChecker extends AbstractChecker { if (required.isEmpty()) error(node, "No jOOQ API usage is allowed at current scope due to conflicting @Require specification."); - x = EnumSet.copyOf(allowed); - x.retainAll(supported); - if (x.isEmpty()) - error(node, "None of the supported dialects (" + supported + ") are allowed in the current scope (" + allowed + ")"); + boolean allowedFail = true; + allowedLoop: + for (SQLDialect a : allowed) { + for (SQLDialect s : supported) { + if (a.supports(s)) { + allowedFail = false; + break allowedLoop; + } + } + } - if (!supported.containsAll(required)) - error(node, "Not all of the required dialects (" + required + ") from the current scope are supported (" + supported + ")"); + if (allowedFail) + error(node, "The allowed dialects in scope " + allowed + " do not include any of the supported dialects: " + supported); + + boolean requiredFail = false; + requiredLoop: + for (SQLDialect r : required) { + for (SQLDialect s : supported) + if (r.supports(s)) + continue requiredLoop; + + requiredFail = true; + break requiredLoop; + } + + if (requiredFail) + error(node, "Not all of the required dialects " + required + " from the current scope are supported " + supported); } } catch (final Exception e) { diff --git a/jOOQ-examples/jOOQ-checker-framework-example/pom.xml b/jOOQ-examples/jOOQ-checker-framework-example/pom.xml index 4ccb2f1cd0..0c9bf259c8 100644 --- a/jOOQ-examples/jOOQ-checker-framework-example/pom.xml +++ b/jOOQ-examples/jOOQ-checker-framework-example/pom.xml @@ -60,7 +60,7 @@ true org.jooq.checker.SQLDialectChecker - org.jooq.checker.PlainSQLChecker + -Xbootclasspath/p:1.8 diff --git a/jOOQ-examples/jOOQ-checker-framework-example/src/main/java/org/jooq/example/checker/SQLDialectCheckerTests.java b/jOOQ-examples/jOOQ-checker-framework-example/src/main/java/org/jooq/example/checker/SQLDialectCheckerTests.java index 1a87611d22..ebcca86072 100644 --- a/jOOQ-examples/jOOQ-checker-framework-example/src/main/java/org/jooq/example/checker/SQLDialectCheckerTests.java +++ b/jOOQ-examples/jOOQ-checker-framework-example/src/main/java/org/jooq/example/checker/SQLDialectCheckerTests.java @@ -1,35 +1,87 @@ package org.jooq.example.checker; import static org.jooq.SQLDialect.H2; +import static org.jooq.SQLDialect.MYSQL; +// ... +import static org.jooq.SQLDialect.POSTGRES; +import static org.jooq.SQLDialect.POSTGRES_9_4; +import static org.jooq.SQLDialect.POSTGRES_9_5; import org.jooq.Allow; import org.jooq.Require; -import org.jooq.SQLDialect; import org.jooq.impl.DSL; -// The class requires both H2 and MySQL -// The inherited @Allow annotation from the package allows only MySQL, though. -@Require({ SQLDialect.H2, SQLDialect.MYSQL }) +// The class requires the H2, MYSQL, and POSTGRES_9_5 families +// The inherited @Allow annotation from the package allows only the MYSQL family, though. +@Require({ H2, MYSQL, POSTGRES_9_5 }) public class SQLDialectCheckerTests { - // @Allow = MySQL (inherited from package) - // @Require = { H2, MySQL } (inherited from class) - public static void doesntCompileBecauseH2IsNotAllowedAndMySQLIsNotSupported() { + // @Allow = MYSQL (inherited from package) + // @Require = { H2, MYSQL, POSTGRES_9_5 } + public static void doesntCompileBecauseOnlyMySQLIsAllowed() { DSL.array(2); } - // @Allow = { H2, MySQL (inherited from package) } - // @Require = { H2, MySQL } (inherited from class) + // @Allow = { MYSQL (inherited from package), POSTGRES_9_4 } + // @Require = { POSTGRES_9_4 } + @Allow(POSTGRES_9_4) + @Require(POSTGRES_9_4) + public static void doesntCompileBecausePostgres95IsNotAllowed() { + DSL.cube(DSL.inline(1)); + } + + // @Allow = { MYSQL (inherited from package), POSTGRES_9_5 } + // @Require = { POSTGRES_9_5 } + @Allow(POSTGRES_9_5) + @Require(POSTGRES_9_5) + public static void compilesBecausePostgres95IsAllowed() { + DSL.cube(DSL.inline(1)); + } + + // @Allow = { MYSQL (inherited from package), POSTGRES } + // @Require = { POSTGRES } + @Allow(POSTGRES) + @Require(POSTGRES) + public static void compilesBecausePostgresIsAllowedAndRequired() { + DSL.cube(DSL.inline(1)); + } + + // @Allow = { MYSQL (inherited from package), POSTGRES } + // @Require = { POSTGRES_9_4 } + @Allow(POSTGRES) + @Require(POSTGRES_9_4) + public static void doesntCompileBecausePostgres94IsRequired() { + DSL.cube(DSL.inline(1)); + } + + // @Allow = { MYSQL (inherited from package), POSTGRES_9_4 } + // @Require = { POSTGRES } + @Allow(POSTGRES_9_4) + @Require(POSTGRES) + public static void compilesBecausePostgres94IsAllowed() { + DSL.lateral(DSL.dual()); + } + + // @Allow = { H2, MYSQL (inherited from package) } + // @Require = { H2, MYSQL, POSTGRES_9_5 } (inherited from class) @Allow(H2) - public static void doesntCompileBecauseMySQLIsNotSupported() { + public static void doesntCompileBecauseMYSQLIsNotSupported() { DSL.array(2); } - // @Allow = { H2, MySQL (inherited from package) } - // @Require = { H2, MySQL } (inherited from class) + // @Allow = { H2, MYSQL (inherited from package) } + // @Require = { H2 } @Allow(H2) @Require(H2) - public static void compiles() { + public static void compilesBecauseH2IsAllowedAndRequired() { + DSL.array(2); + } + + // @Allow = { H2, MYSQL (inherited from package) } + // @Require = { H2 } + @Allow(H2) + @Require({ H2, ORACLE }) + public static void doesntCompileAsOracleCannotBeRequiredInScope() { DSL.array(2); } } diff --git a/jOOQ/src/main/java/org/jooq/Allow.java b/jOOQ/src/main/java/org/jooq/Allow.java index 0137bb81ef..10d9de5c36 100644 --- a/jOOQ/src/main/java/org/jooq/Allow.java +++ b/jOOQ/src/main/java/org/jooq/Allow.java @@ -122,8 +122,8 @@ import java.lang.annotation.Target; *
    *
  • In the absence of any {@link Allow} annotation, no jOOQ API usage is * allowed.
  • - *
  • The combination of all {@link Allow} and {@link Require} annotations is - * applied for any given scope.
  • + *
  • The combination of all {@link Allow} annotations and of the inner-most + * {@link Require} annotation is applied for any given scope.
  • *
  • Nested packages are not creating nested scopes.
  • *
  • If a versioned {@link SQLDialect} is allowed (rather than a * {@link SQLDialect#family()}), then the allowed version, all of its diff --git a/jOOQ/src/main/java/org/jooq/Require.java b/jOOQ/src/main/java/org/jooq/Require.java index f4ac9034f0..d87d44f9cc 100644 --- a/jOOQ/src/main/java/org/jooq/Require.java +++ b/jOOQ/src/main/java/org/jooq/Require.java @@ -103,8 +103,8 @@ import java.lang.annotation.Target; *
      *
    • In the absence of any {@link Allow} annotation, no jOOQ API usage is * allowed.
    • - *
    • The combination of all {@link Allow} and {@link Require} annotations is - * applied for any given scope.
    • + *
    • The combination of all {@link Allow} annotations and of the inner-most + * {@link Require} annotation is applied for any given scope.
    • *
    • Nested packages are not creating nested scopes.
    • *
    • If a versioned {@link SQLDialect} is required (rather than a * {@link SQLDialect#family()}), then the required version, any of its