Adding support for generating DAOBean as annotated Spring Bean.

Add spring boot config and usage to readme.md
This commit is contained in:
jbriggs3 2018-09-27 14:57:03 -04:00
parent fad614f85a
commit d2a79e3a65
7 changed files with 151 additions and 1 deletions

View File

@ -48,6 +48,13 @@ public interface JdbcMapper extends Closeable {
DatabaseType databaseType() default DatabaseType.DEFAULT;
String arrayNumberTypeName() default "";
String arrayStringTypeName() default "";
/**
* Allows consumer of JdbcMapper.Mapper to generate DaoBean with Spring Boot Stereotype @Repository
* Defaults to false
* @return
*/
OptionalBool generateAsSpringBean() default OptionalBool.FALSE;
}
@Retention(RetentionPolicy.SOURCE)

View File

@ -10,6 +10,7 @@ import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import java.io.*;
import java.net.URL;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
@ -30,7 +31,7 @@ import static com.moparisthebest.jdbc.codegen.JdbcMapperFactory.SUFFIX;
* Created by mopar on 5/24/17.
*/
@SupportedAnnotationTypes("com.moparisthebest.jdbc.codegen.JdbcMapper.Mapper")
@SupportedOptions({"jdbcMapper.databaseType", "jdbcMapper.arrayNumberTypeName", "jdbcMapper.arrayStringTypeName", "jdbcMapper.allowedMaxRowParamNames", "jdbcMapper.sqlCheckerClass"})
@SupportedOptions({"jdbcMapper.databaseType", "jdbcMapper.arrayNumberTypeName", "jdbcMapper.arrayStringTypeName", "jdbcMapper.allowedMaxRowParamNames", "jdbcMapper.sqlCheckerClass", "jdbcMapper.generateAsSpringBean"})
public class JdbcMapperProcessor extends AbstractProcessor {
public static final Pattern paramPattern = Pattern.compile("\\{(([^\\s]+)\\s+(([Nn][Oo][Tt]\\s+)?[Ii][Nn]\\s+))?([BbCc][Ll][Oo][Bb]\\s*:\\s*([^:}]+\\s*:\\s*)?)?([^}]+)\\}");
@ -171,6 +172,8 @@ public class JdbcMapperProcessor extends AbstractProcessor {
final JdbcMapper.Mapper mapper = genClass.getAnnotation(JdbcMapper.Mapper.class);
final JdbcMapper.DatabaseType databaseType;
final String arrayNumberTypeName, arrayStringTypeName;
final boolean generateAsSpringBean = mapper.generateAsSpringBean().combine(false);
if (mapper.databaseType() == JdbcMapper.DatabaseType.DEFAULT) {
databaseType = defaultDatabaseType;
arrayNumberTypeName = !mapper.arrayNumberTypeName().isEmpty() ? mapper.arrayNumberTypeName() : defaultArrayNumberTypeName;
@ -223,10 +226,16 @@ public class JdbcMapperProcessor extends AbstractProcessor {
w.write(packageName);
w.write(";\n\n");
}
if (generateAsSpringBean) {
w.write("import org.springframework.stereotype.Repository;\n\n");
}
w.write("import com.moparisthebest.jdbc.Factory;\n\n");
w.write("import java.sql.*;\n\n");
w.write("import static com.moparisthebest.jdbc.util.ResultSetUtil.*;\n");
w.write("import static com.moparisthebest.jdbc.TryClose.tryClose;\n\n");
if (generateAsSpringBean) {
w.write("@Repository\n");
}
w.write("public class ");
w.write(className);
if (isInterface) {
@ -1105,4 +1114,13 @@ public class JdbcMapperProcessor extends AbstractProcessor {
}
return false;
}
private final boolean isSpringRepositoryStereotypeRequired(final String stereoType) {
if (Boolean.parseBoolean(processingEnv.getOptions().get("jdbcMapper.generateAsSpringBean"))) {
return processingEnv.getOptions().get("jdbcMapper.springBeanStereotype").equalsIgnoreCase(stereoType);
}
return false;
}
}

View File

@ -411,6 +411,49 @@ String s = rs.getString(index);
return s == null ? null : ZoneOffset.of(s);
```
Spring Boot Support
----
Configuring your `JdbcMapperProcessor` generated `DAOBean` to be compatible with Spring's [ComponentScan](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/ComponentScan.html) can be
accomplished by simply setting the `JdbcMapper.Mapper.generateAsSpringBean` value to
`JdbcMapper.OptionalBool.TRUE`. This value is set to `JdbcMapper.OptionalBool.FALSE` by default.
```java
@JdbcMapper.Mapper(generateAsSpringBean = JdbcMapper.OptionalBool.TRUE)
public interface MyDAO extends JdbcMapper {
// Your method signatures and queries here
}
```
This configuration will generate a DAOBean looking something like this:
```java
package com.yourpackage;
import org.springframework.stereotype.Repository;
import com.moparisthebest.jdbc.Factory;
import java.sql.*;
import static com.moparisthebest.jdbc.util.ResultSetUtil.*;
import static com.moparisthebest.jdbc.TryClose.tryClose;
@Repository
public class MyDAOBean implements MyDAO {
// Generated code here
}
```
Your DAOBean can now be [Autowired](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html)
in a Spring Boot application:
```java
private final MyDAO myDAO;
@Autowired
public MyController(MyDAO myDAO) {
this.myDAO = myDAO;
}
```
TODO
----

View File

@ -80,6 +80,11 @@
<scope>test</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.9.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>

View File

@ -0,0 +1,9 @@
package com.moparisthebest.jdbc.codegen;
@JdbcMapper.Mapper(jndiName = "bob",
databaseType = JdbcMapper.DatabaseType.ANY,
cachePreparedStatements = JdbcMapper.OptionalBool.FALSE,
allowReflection = JdbcMapper.OptionalBool.TRUE,
generateAsSpringBean = JdbcMapper.OptionalBool.TRUE)
public abstract class AbstractSpringBeanDAO implements JdbcMapper {
}

View File

@ -0,0 +1,9 @@
package com.moparisthebest.jdbc.codegen;
@JdbcMapper.Mapper(jndiName = "bob",
databaseType = JdbcMapper.DatabaseType.ANY,
cachePreparedStatements = JdbcMapper.OptionalBool.FALSE,
allowReflection = JdbcMapper.OptionalBool.TRUE,
generateAsSpringBean = JdbcMapper.OptionalBool.TRUE)
public interface SpringBeanDAO extends JdbcMapper {
}

View File

@ -0,0 +1,59 @@
package com.moparisthebest.jdbc.codegen;
import org.junit.Test;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertFalse;
public class SpringBeanDAOTest {
@Test
public void testSpringBeanDAOBeanImportsRepository() {
try {
String genClass = new String(Files.readAllBytes(Paths.get("target/generated-sources/annotations/com/moparisthebest/jdbc/codegen/SpringBeanDAOBean.java")), StandardCharsets.UTF_8);
assertTrue(genClass.contains("import org.springframework.stereotype.Repository;"));
} catch (IOException e) {
assertFalse("Failed to read file at target/generated-sources/annotations/com/moparisthebest/jdbc/codegen/SpringBeanDAOBean.java", true);
}
}
@Test
public void testSpringBeanDAOHasRepositoryStereotype() {
try {
Class clazz = ClassLoader.getSystemClassLoader()
.loadClass("com.moparisthebest.jdbc.codegen.SpringBeanDAOBean");
assertTrue(clazz.isAnnotationPresent(org.springframework.stereotype.Repository.class));
} catch (ClassNotFoundException e) {
assertFalse("Failed to find class com.moparisthebest.jdbc.codegen.SpringBeanDAOBean", true);
}
}
@Test
public void testSpringBeanDAOBeanImplementsSpringBeanDAO() {
try {
Class[] clazzInterfaces = ClassLoader.getSystemClassLoader()
.loadClass("com.moparisthebest.jdbc.codegen.SpringBeanDAOBean").getInterfaces();
assertTrue(Arrays.asList(clazzInterfaces).contains(SpringBeanDAO.class));
} catch (ClassNotFoundException e) {
assertFalse("Failed to find class com.moparisthebest.jdbc.codegen.SpringBeanDAOBean", true);
}
}
@Test
public void testAbstractSpringBeanDAOBeanExtendsAbstractSpringBeanDAO() {
try {
Class clazz = ClassLoader.getSystemClassLoader()
.loadClass("com.moparisthebest.jdbc.codegen.AbstractSpringBeanDAOBean");
assertTrue(clazz.getSuperclass().equals(AbstractSpringBeanDAO.class));
} catch (ClassNotFoundException e) {
assertFalse("Failed to find class com.moparisthebest.jdbc.codegen.AbstractSpringBeanDAOBean", true);
}
}
}