[#5245] Add org.jooq.Allow and org.jooq.Require annotation and a SQLDialectChecker using JSR-308 and the checker framework

This commit is contained in:
lukaseder 2016-05-09 12:12:32 +02:00
parent 09344c4d45
commit ae40bd5c27
21 changed files with 846 additions and 0 deletions

3
jOOQ-checker/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target
/.idea
/*.iml

22
jOOQ-checker/LICENSE.txt Normal file
View File

@ -0,0 +1,22 @@
Copyright (c) 2009-2016, Data Geekery GmbH (http://www.datageekery.com)
All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Other licenses:
-----------------------------------------------------------------------------
Commercial licenses for this work are available. These replace the above
ASL 2.0 and offer limited warranties, support, maintenance, and commercial
database integrations.
For more information, please visit: http://www.jooq.org/licenses

45
jOOQ-checker/pom.xml Normal file
View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jooq</groupId>
<artifactId>jooq-parent</artifactId>
<version>3.9.0-SNAPSHOT</version>
</parent>
<groupId>org.jooq</groupId>
<artifactId>jooq-checker</artifactId>
<name>jOOQ Checker</name>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.jooq.org/inc/LICENSE.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<dependencies>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
</dependency>
<dependency>
<groupId>org.checkerframework</groupId>
<artifactId>checker</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,156 @@
/**
* Copyright (c) 2009-2016, Data Geekery GmbH (http://www.datageekery.com)
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.checker;
import static com.sun.source.util.TreePath.getPath;
import static java.util.Arrays.asList;
import static org.checkerframework.javacutil.TreeUtils.elementFromDeclaration;
import static org.checkerframework.javacutil.TreeUtils.elementFromUse;
import static org.checkerframework.javacutil.TreeUtils.enclosingMethod;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.EnumSet;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import org.jooq.Allow;
import org.jooq.Require;
import org.jooq.SQLDialect;
import org.jooq.Support;
import org.checkerframework.framework.source.Result;
import org.checkerframework.framework.source.SourceChecker;
import org.checkerframework.framework.source.SourceVisitor;
import com.sun.source.tree.MethodInvocationTree;
/**
* A checker to compare {@link SQLDialect} from a use-site {@link Require}
* annotation with a declaration-site {@link Support} annotation.
*
* @author Lukas Eder
*/
public class SQLDialectChecker extends SourceChecker {
@Override
protected SourceVisitor<?, ?> createSourceVisitor() {
return new SourceVisitor<Void, Void>(this) {
@Override
public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
try {
ExecutableElement elementFromUse = elementFromUse(node);
Support support = elementFromUse.getAnnotation(Support.class);
// In the absence of a @Support annotation, or if no SQLDialect is supplied,
// all jOOQ API method calls will type check.
if (support != null && support.value().length > 0) {
Element enclosing = elementFromDeclaration(enclosingMethod(getPath(root, node)));
EnumSet<SQLDialect> supported = EnumSet.copyOf(asList(support.value()));
EnumSet<SQLDialect> allowed = EnumSet.noneOf(SQLDialect.class);
EnumSet<SQLDialect> required = EnumSet.allOf(SQLDialect.class);
EnumSet<SQLDialect> x;
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()));
enclosing = enclosing.getEnclosingElement();
}
if (allowed.isEmpty())
error(node, "No jOOQ API usage is allowed at current scope. Use @Allow.");
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 + ")");
if (!supported.containsAll(required))
error(node, "Not all of the required dialects (" + required + ") from the current scope are supported (" + supported + ")");
}
}
catch (final Exception e) {
print(new Printer() {
@Override
public void print(PrintWriter t) {
e.printStackTrace(t);
}
});
}
return super.visitMethodInvocation(node, p);
}
};
}
void error(Object node, String message) {
getChecker().report(Result.failure(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.");
writer.println("Please report this bug here: https://github.com/jOOQ/jOOQ/issues/new");
writer.println("---------------------------------------------------------------------");
printer.print(writer);
}
catch (IOException ignore) {}
}
interface Printer {
void print(PrintWriter writer);
}
}

View File

@ -0,0 +1,9 @@
/**
* This package contains useful checkers that work with JSR 308 and the checker
* framework.
*
* @author Lukas Eder
* @see <a href="http://types.cs.washington.edu/checker-framework">http://types.
* cs.washington.edu/checker-framework</a>
*/
package org.jooq.checker;

View File

@ -0,0 +1,22 @@
Copyright (c) 2009-2016, Data Geekery GmbH (http://www.datageekery.com)
All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Other licenses:
-----------------------------------------------------------------------------
Commercial licenses for this work are available. These replace the above
ASL 2.0 and offer limited warranties, support, maintenance, and commercial
database integrations.
For more information, please visit: http://www.jooq.org/licenses

View File

@ -0,0 +1,2 @@
Thanks for downloading jOOQ.
Please visit http://www.jooq.org for more information.

View File

@ -0,0 +1,2 @@
/target
/jooq-flyway-example.iml

View File

@ -0,0 +1,22 @@
Copyright (c) 2009-2016, Data Geekery GmbH (http://www.datageekery.com)
All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Other licenses:
-----------------------------------------------------------------------------
Commercial licenses for this work are available. These replace the above
ASL 2.0 and offer limited warranties, support, maintenance, and commercial
database integrations.
For more information, please visit: http://www.jooq.org/licenses

View File

@ -0,0 +1,12 @@
Thanks for downloading jOOQ.
Please visit http://www.jooq.org for more information.
To install and run this example, simply check it out and run the following Maven command
```
$ pwd
/path/to/checkout/dir
$ cd jOOQ-examples/jOOQ-flyway-example
...
$ mvn clean install
```

View File

@ -0,0 +1,37 @@
java.lang.NullPointerException
at org.jooq.checker.SQLDialectChecker$1.visitMethodInvocation(SQLDialectChecker.java:101)
at org.jooq.checker.SQLDialectChecker$1.visitMethodInvocation(SQLDialectChecker.java:79)
at com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1477)
at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:68)
at com.sun.source.util.TreeScanner.visitExpressionStatement(TreeScanner.java:243)
at com.sun.tools.javac.tree.JCTree$JCExpressionStatement.accept(JCTree.java:1302)
at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:68)
at com.sun.source.util.TreeScanner.scan(TreeScanner.java:91)
at com.sun.source.util.TreeScanner.visitBlock(TreeScanner.java:162)
at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:918)
at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:68)
at com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:81)
at com.sun.source.util.TreeScanner.visitMethod(TreeScanner.java:144)
at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:800)
at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:68)
at com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:81)
at com.sun.source.util.TreeScanner.scan(TreeScanner.java:91)
at com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:99)
at com.sun.source.util.TreeScanner.visitClass(TreeScanner.java:133)
at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:720)
at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:50)
at org.checkerframework.framework.source.SourceVisitor.visit(SourceVisitor.java:70)
at org.checkerframework.framework.source.SourceChecker.typeProcess(SourceChecker.java:939)
at org.checkerframework.javacutil.AbstractTypeProcessor$AttributionTaskListener.finished(AbstractTypeProcessor.java:209)
at com.sun.tools.javac.api.ClientCodeWrapper$WrappedTaskListener.finished(ClientCodeWrapper.java:681)
at com.sun.tools.javac.api.MultiTaskListener.finished(MultiTaskListener.java:111)
at com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1342)
at com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1296)
at com.sun.tools.javac.main.JavaCompiler.compile2(JavaCompiler.java:901)
at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:860)
at com.sun.tools.javac.main.Main.compile(Main.java:523)
at com.sun.tools.javac.main.Main.compile(Main.java:381)
at com.sun.tools.javac.main.Main.compile(Main.java:370)
at com.sun.tools.javac.main.Main.compile(Main.java:361)
at com.sun.tools.javac.Main.compile(Main.java:56)
at com.sun.tools.javac.Main.main(Main.java:42)

View File

@ -0,0 +1,71 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.jooq</groupId>
<artifactId>jooq-checker-framework-example</artifactId>
<version>3.9.0-SNAPSHOT</version>
<name>jOOQ Checker Framework Example</name>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.jooq.org/inc/LICENSE.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<org.jooq.version>3.9.0-SNAPSHOT</org.jooq.version>
</properties>
<dependencies>
<!-- Database access -->
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
<version>${org.jooq.version}</version>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq-checker</artifactId>
<version>${org.jooq.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<fork>true</fork>
<annotationProcessors>
<annotationProcessor>org.jooq.checker.SQLDialectChecker</annotationProcessor>
</annotationProcessors>
<compilerArgs>
<arg>-Xbootclasspath/p:1.8</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,35 @@
package org.jooq.example.checker;
import static org.jooq.SQLDialect.H2;
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 })
public class CheckerTests {
// @Allow = MySQL (inherited from package)
// @Require = { H2, MySQL } (inherited from class)
public static void doesntCompileBecauseH2IsNotAllowedAndMySQLIsNotSupported() {
DSL.array(2);
}
// @Allow = { H2, MySQL (inherited from package) }
// @Require = { H2, MySQL } (inherited from class)
@Allow(H2)
public static void doesntCompileBecauseMySQLIsNotSupported() {
DSL.array(2);
}
// @Allow = { H2, MySQL (inherited from package) }
// @Require = { H2, MySQL } (inherited from class)
@Allow(H2)
@Require(H2)
public static void compiles() {
DSL.array(2);
}
}

View File

@ -0,0 +1,47 @@
package org.jooq.example.checker;
import static org.jooq.example.checker.db.h2.Tables.AUTHOR;
import static org.jooq.example.checker.db.h2.Tables.BOOK;
import java.sql.Connection;
import java.sql.DriverManager;
import org.jooq.Require;
import org.jooq.Result;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;
/**
* @author Lukas Eder
*/
@Require(
value = { SQLDialect.H2, SQLDialect.MYSQL }
)
public class ShouldntCompile {
@Require({SQLDialect.H2, SQLDialect.MYSQL})
public static void main(String[] args) throws Exception {
try (Connection c = DriverManager.getConnection("jdbc:h2:~/checker-test", "sa", "")) {
Result<?> result =
DSL.using(c)
.select(
AUTHOR.FIRST_NAME,
AUTHOR.LAST_NAME,
BOOK.ID,
BOOK.TITLE,
DSL.array(1)
)
.from(AUTHOR)
.join(BOOK)
.on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
.connectBy("abc")
.orderBy(BOOK.ID.asc())
.fetch();
System.out.println(result);
}
}
public static void x() {
DSL.array(2);
}
}

View File

@ -0,0 +1,11 @@
/**
* Enable jOOQ API usage with MySQL for the whole package.
*
* @author Lukas Eder
*/
@Allow(MYSQL)
package org.jooq.example.checker;
import static org.jooq.SQLDialect.MYSQL;
import org.jooq.Allow;

View File

@ -0,0 +1,3 @@
DROP SCHEMA IF EXISTS checker;
CREATE SCHEMA checker;

View File

@ -0,0 +1,12 @@
CREATE SEQUENCE checker.s_author_id START WITH 1;
CREATE TABLE checker.author (
id INT NOT NULL,
first_name VARCHAR(50),
last_name VARCHAR(50) NOT NULL,
date_of_birth DATE,
year_of_birth INT,
address VARCHAR(50),
CONSTRAINT pk_t_author PRIMARY KEY (ID)
);

View File

@ -0,0 +1,17 @@
CREATE TABLE checker.book (
id INT NOT NULL,
author_id INT NOT NULL,
title VARCHAR(400) NOT NULL,
CONSTRAINT pk_t_book PRIMARY KEY (id),
CONSTRAINT fk_t_book_author_id FOREIGN KEY (author_id) REFERENCES author(id)
);
INSERT INTO checker.author VALUES (next value for checker.s_author_id, 'George', 'Orwell', '1903-06-25', 1903, null);
INSERT INTO checker.author VALUES (next value for checker.s_author_id, 'Paulo', 'Coelho', '1947-08-24', 1947, null);
INSERT INTO checker.book VALUES (1, 1, '1984');
INSERT INTO checker.book VALUES (2, 1, 'Animal Farm');
INSERT INTO checker.book VALUES (3, 2, 'O Alquimista');
INSERT INTO checker.book VALUES (4, 2, 'Brida');

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd" >
<log4j:configuration>
<appender name="stdout" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ABSOLUTE} %5p [%-50c{4}] - %m%n" />
</layout>
</appender>
<root>
<priority value="debug" />
<appender-ref ref="stdout" />
</root>
</log4j:configuration>

View File

@ -0,0 +1,175 @@
/**
* Copyright (c) 2009-2016, Data Geekery GmbH (http://www.datageekery.com)
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PACKAGE;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
// ...
// ...
import static org.jooq.SQLDialect.CUBRID;
// ...
import static org.jooq.SQLDialect.DEFAULT;
import static org.jooq.SQLDialect.DERBY;
import static org.jooq.SQLDialect.FIREBIRD;
import static org.jooq.SQLDialect.H2;
// ...
import static org.jooq.SQLDialect.HSQLDB;
// ...
// ...
import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
// ...
import static org.jooq.SQLDialect.POSTGRES;
// ...
import static org.jooq.SQLDialect.SQL99;
import static org.jooq.SQLDialect.SQLITE;
// ...
// ...
// ...
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* Allow a set of {@link SQLDialect} to be supported by any jOOQ statement in
* the scope of this annotation.
* <p>
* This annotation can be used at the use-site of jOOQ API at any given scope
* {@link ElementType#PACKAGE}, {@link ElementType#TYPE},
* {@link ElementType#METHOD} in order to specify that the given scope allows
* ANY of the supplied {@link SQLDialect} to be supported by all usage of jOOQ
* API within the scope. For example:
* <p>
* <code><pre>
* // Allow only MYSQL or ORACLE dialect support to be used within the class scope
* &#64;Allow(MYSQL, ORACLE)
* public class MySQLAndOracleDAO {
*
* // Allow rule from class applies to this method
* public void mysqlAndOracleMethod() {
* DSL.using(configuration)
* .insertInto(TABLE, TABLE.COLUMN)
* .values(1)
* // This type checks as it works on both MySQL and Oracle
* .onDuplicateKeyUpdate()
* .set(TABLE.COLUMN, 2)
* .execute();
* }
*
* // Refine class Allow rule with additional requirement
* &#64;Require(ORACLE)
* public void oracleOnlyMethod() {
* DSL.using(configuration)
* .mergeInto(TABLE)
* .using(selectOne())
* .on(TABLE.COLUMN.eq(1))
* .whenMatchedThenUpdate()
* .set(TABLE.COLUMN, 2)
* .whenNotMatchedThenInsert(TABLE.COLUMN)
* .values(1)
* .execute();
* }
* }
* </pre></code>
* <p>
* Type checking for these annotations can be supplied by
* <code>org.jooq.checker.SQLDialectChecker</code> from the jOOQ-checker module.
* <h2>Rules:</h2>
* <ul>
* <li>In the absence of any {@link Allow} annotation, no jOOQ API usage is
* allowed.</li>
* <li>The combination of all {@link Allow} and {@link Require} annotations is
* applied for any given scope.</li>
* <li>Nested packages are not creating nested scopes.</li>
* <li>If a versioned {@link SQLDialect} is allowed (rather than a
* {@link SQLDialect#family()}), then the allowed version, all of its
* {@link SQLDialect#predecessor()}, and its {@link SQLDialect#family()} are
* allowed.</li>
* </ul>
*
* @author Lukas Eder
* @see Require
*/
@Target({ METHOD, CONSTRUCTOR, TYPE, PACKAGE })
@Retention(RUNTIME)
@Documented
@Inherited
public @interface Allow {
/**
* A list of jOOQ {@link SQLDialect} which are required on any jOOQ API
* method that is annotated with {@link Support}.
*/
@SuppressWarnings("deprecation")
SQLDialect[] value() default {
CUBRID,
DEFAULT,
SQL99,
DERBY,
FIREBIRD,
H2,
HSQLDB,
MARIADB,
MYSQL,
POSTGRES,
SQLITE,
};
}

View File

@ -0,0 +1,129 @@
/**
* Copyright (c) 2009-2016, Data Geekery GmbH (http://www.datageekery.com)
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PACKAGE;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* Require a set of {@link SQLDialect} to be supported by any jOOQ statement in
* the scope of this annotation.
* <p>
* This annotation can be used at the use-site of jOOQ API at any given scope
* {@link ElementType#PACKAGE}, {@link ElementType#TYPE},
* {@link ElementType#METHOD} in order to specify that the given scope requires
* ALL of the supplied {@link SQLDialect} to be supported by all usage of jOOQ
* API within the scope. For example:
* <p>
* <code><pre>
* // Allow only MYSQL or ORACLE dialect support to be used within the class scope
* &#64;Allow(MYSQL, ORACLE)
* public class MySQLAndOracleDAO {
*
* // Allow rule from class applies to this method
* public void mysqlAndOracleMethod() {
* DSL.using(configuration)
* .insertInto(TABLE, TABLE.COLUMN)
* .values(1)
* // This type checks as it works on both MySQL and Oracle
* .onDuplicateKeyUpdate()
* .set(TABLE.COLUMN, 2)
* .execute();
* }
*
* // Refine class Allow rule with additional requirement
* &#64;Require(ORACLE)
* public void oracleOnlyMethod() {
* DSL.using(configuration)
* .mergeInto(TABLE)
* .using(selectOne())
* .on(TABLE.COLUMN.eq(1))
* .whenMatchedThenUpdate()
* .set(TABLE.COLUMN, 2)
* .whenNotMatchedThenInsert(TABLE.COLUMN)
* .values(1)
* .execute();
* }
* }
* </pre></code>
* <p>
* Type checking for these annotations can be supplied by
* <code>org.jooq.checker.SQLDialectChecker</code> from the jOOQ-checker module.
* <p>
* Type checking for these annotations can be supplied by
* <code>org.jooq.checker.SQLDialectChecker</code> from the jOOQ-checker module.
* <h2>Rules:</h2>
* <ul>
* <li>In the absence of any {@link Allow} annotation, no jOOQ API usage is
* allowed.</li>
* <li>The combination of all {@link Allow} and {@link Require} annotations is
* applied for any given scope.</li>
* <li>Nested packages are not creating nested scopes.</li>
* <li>If a versioned {@link SQLDialect} is required (rather than a
* {@link SQLDialect#family()}), then the required version, any of its
* {@link SQLDialect#predecessor()}, or its {@link SQLDialect#family()} are
* required.</li>
* </ul>
*
* @author Lukas Eder
* @see Allow
*/
@Target({ METHOD, CONSTRUCTOR, TYPE, PACKAGE })
@Retention(RUNTIME)
@Documented
@Inherited
public @interface Require {
/**
* A list of jOOQ {@link SQLDialect} which are required on any jOOQ API
* method that is annotated with {@link Support}.
*/
SQLDialect[] value() default {};
}