Skip to content

Commit c67a1a0

Browse files
authored
Merge pull request #225 from domaframework/feat/configuration
Add domaCodeGen configuration for improved dependency management
2 parents 455657d + 1a22007 commit c67a1a0

File tree

6 files changed

+218
-23
lines changed

6 files changed

+218
-23
lines changed

codegen-test/build.gradle.kts

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import org.h2.Driver
21
import org.seasar.doma.gradle.codegen.desc.LanguageType
3-
import org.seasar.doma.gradle.codegen.jdbc.SimpleDataSource
42

53
buildscript {
64
repositories {
@@ -11,10 +9,7 @@ buildscript {
119
}
1210
}
1311
dependencies {
14-
val h2Version: String = properties["h2Version"] as String
1512
classpath("org.domaframework.doma:codegen")
16-
classpath("com.h2database:h2:$h2Version")
17-
classpath("mysql:mysql-connector-java:8.0.33")
1813
}
1914
}
2015

@@ -23,6 +18,7 @@ plugins {
2318
id("org.jetbrains.kotlin.jvm") version "2.2.0"
2419
id("org.domaframework.doma.compile") version "4.0.0"
2520
id("org.domaframework.doma.codegen")
21+
id("com.nocwriter.runsql") version "1.0.3"
2622
}
2723

2824
java {
@@ -40,13 +36,19 @@ dependencies {
4036

4137
implementation("org.seasar.doma:doma-core:$domaVersion")
4238
annotationProcessor("org.seasar.doma:doma-processor:$domaVersion")
43-
39+
4440
// Use JUnit BOM for version management
4541
testImplementation(platform("org.junit:junit-bom:5.13.2"))
4642
testImplementation("org.junit.jupiter:junit-jupiter-api")
4743
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
4844
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
4945
testRuntimeOnly("com.h2database:h2:$h2Version")
46+
47+
// Add H2 to the domaCodeGen configuration
48+
domaCodeGen("com.h2database:h2:$h2Version")
49+
50+
// Used by runsql-gradle-plugin
51+
runtimeOnly("com.h2database:h2:$h2Version")
5052
}
5153

5254
val _url = "jdbc:h2:file:$projectDir/data/db"
@@ -92,15 +94,13 @@ tasks {
9294
}
9395
}
9496

95-
val createDb = register("createDb") {
96-
doLast {
97-
val ds = SimpleDataSource()
98-
ds.setDriver(Driver())
99-
ds.setUrl(_url)
100-
ds.setUser(_user)
101-
ds.setPassword(_password)
102-
103-
val sql = """
97+
val createDb = register<RunSQL>("createDb") {
98+
config {
99+
username = _user
100+
password = _password
101+
url = _url
102+
driverClassName = "org.h2.Driver"
103+
script = """
104104
drop all objects;
105105
106106
create table department(
@@ -115,13 +115,8 @@ tasks {
115115
employee_id integer not null primary key,
116116
employee_no integer not null,
117117
employee_name varchar(20)
118-
);
119-
"""
120-
ds.connection.use {
121-
it.createStatement().use {
122-
it.execute(sql)
123-
}
124-
}
118+
);
119+
""".trimIndent()
125120
}
126121
}
127122

codegen/src/main/java/org/seasar/doma/gradle/codegen/CodeGenPlugin.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
public class CodeGenPlugin implements Plugin<Project> {
2121

2222
public static final String EXTENSION_NAME = "domaCodeGen";
23+
public static final String CONFIGURATION_NAME = "domaCodeGen";
2324
public static final String TASK_GROUP_NAME = "Doma Code Generation";
2425
public static final String DB_META_TASK_NAME = "DbMeta";
2526
public static final String DTO_TASK_NAME = "Dto";
@@ -33,6 +34,18 @@ public class CodeGenPlugin implements Plugin<Project> {
3334

3435
@Override
3536
public void apply(Project project) {
37+
project
38+
.getConfigurations()
39+
.create(
40+
CONFIGURATION_NAME,
41+
config -> {
42+
config.setDescription(
43+
"The libraries used by the Doma CodeGen plugin for JDBC drivers and other dependencies");
44+
config.setVisible(false);
45+
config.setCanBeConsumed(false);
46+
config.setCanBeResolved(true);
47+
});
48+
3649
NamedDomainObjectContainer<CodeGenConfig> container =
3750
project.container(
3851
CodeGenConfig.class,

codegen/src/main/java/org/seasar/doma/gradle/codegen/extension/CodeGenConfig.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
package org.seasar.doma.gradle.codegen.extension;
22

3+
import static org.seasar.doma.gradle.codegen.CodeGenPlugin.CONFIGURATION_NAME;
4+
35
import java.io.File;
6+
import java.net.URL;
7+
import java.net.URLClassLoader;
48
import java.nio.charset.StandardCharsets;
59
import java.sql.Driver;
610
import java.util.Collections;
711
import java.util.List;
12+
import java.util.Set;
813
import javax.inject.Inject;
914
import javax.sql.DataSource;
1015
import org.gradle.api.Action;
1116
import org.gradle.api.Project;
17+
import org.gradle.api.artifacts.Configuration;
1218
import org.gradle.api.file.Directory;
1319
import org.gradle.api.file.DirectoryProperty;
1420
import org.gradle.api.file.FileTree;
@@ -31,6 +37,8 @@ public class CodeGenConfig {
3137

3238
private final String name;
3339

40+
private final Configuration configuration;
41+
3442
private final Property<GlobalFactory> globalFactory;
3543

3644
private final Property<DataSource> dataSource;
@@ -85,6 +93,8 @@ public class CodeGenConfig {
8593
public CodeGenConfig(String name, Project project) {
8694
this.name = name;
8795

96+
this.configuration = project.getConfigurations().getByName(CONFIGURATION_NAME);
97+
8898
ObjectFactory objects = project.getObjects();
8999

90100
globalFactory = objects.property(GlobalFactory.class);
@@ -146,13 +156,32 @@ private Provider<DataSource> dataSourceProvider() {
146156
if (driverClassName == null) {
147157
throw new CodeGenException(Message.DOMAGEN0024);
148158
}
149-
Driver driver = ClassUtil.newInstance(Driver.class, driverClassName, "driverClassName");
159+
ClassLoader classLoader = createClassLoader();
160+
Driver driver =
161+
ClassUtil.newInstance(Driver.class, driverClassName, "driverClassName", classLoader);
150162
return globalFactory
151163
.get()
152164
.createDataSource(driver, user.getOrNull(), password.getOrNull(), url.get());
153165
});
154166
}
155167

168+
protected ClassLoader createClassLoader() {
169+
if (configuration == null || configuration.isEmpty()) {
170+
return getClass().getClassLoader();
171+
}
172+
Set<File> fileSet = configuration.getFiles();
173+
URL[] urls = new URL[fileSet.size()];
174+
int i = 0;
175+
for (File file : fileSet) {
176+
try {
177+
urls[i++] = file.toURI().toURL();
178+
} catch (Exception e) {
179+
throw new RuntimeException("Failed to convert file to URL: " + file, e);
180+
}
181+
}
182+
return new URLClassLoader(urls, getClass().getClassLoader());
183+
}
184+
156185
private Provider<CodeGenDialect> codeGenDialectProvider() {
157186
return url.map(
158187
it -> {

codegen/src/main/java/org/seasar/doma/gradle/codegen/message/Message.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ public enum Message implements MessageResource {
2626
"Cannot infer the driver class name from the property \"url\", so this plugin cannot create a DataSource instance. Correct the url property or specify the property \"dataSource\" explicitly."),
2727
DOMAGEN0025(
2828
"Cannot infer the dialect name from the property \"url\", so this plugin cannot create a CodeGenDialect instance. Correct the url property or specify the property \"codeGenDialect\" explicitly."),
29+
DOMAGEN0033("The class \"{1}\" to which the parameter \"{0}\" refers is not found. {2}"),
30+
DOMAGEN0034(
31+
"The class \"{1}\" to which the parameter \"{0}\" refers must be a subtype of the class \"{2}\"."),
32+
DOMAGEN0035(
33+
"The class \"{1}\" to which the parameter \"{0}\" refers cannot be instantiated. The class \"{1}\" must have a public default constructor. {2}"),
2934

3035
DOMAGEN5001(
3136
"The JDBC driver may not be loaded. Check that the JDBC driver is in the classpath. If the JDBC driver is not loaded automatically, load it explicitly using Class.forName. ex) Class.forName(\"oracle.jdbc.driver.OracleDriver\")"),

codegen/src/main/java/org/seasar/doma/gradle/codegen/util/ClassUtil.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,20 @@ public static <T> T newInstance(Class<T> supertype, String className, String pro
6868
}
6969
}
7070

71+
public static <T> T newInstance(
72+
Class<T> supertype, String className, String propertyName, ClassLoader classLoader) {
73+
AssertionUtil.assertNotNull(supertype, className, propertyName, classLoader);
74+
Class<?> clazz = forName(className, propertyName, classLoader);
75+
if (!supertype.isAssignableFrom(clazz)) {
76+
throw new CodeGenException(Message.DOMAGEN0034, propertyName, className, supertype.getName());
77+
}
78+
try {
79+
return supertype.cast(clazz.getDeclaredConstructor().newInstance());
80+
} catch (ReflectiveOperationException e) {
81+
throw new CodeGenException(Message.DOMAGEN0035, propertyName, className, e);
82+
}
83+
}
84+
7185
public static Class<?> forName(String className, String propertyName) {
7286
AssertionUtil.assertNotNull(className, propertyName);
7387
try {
@@ -76,4 +90,13 @@ public static Class<?> forName(String className, String propertyName) {
7690
throw new CodeGenException(Message.DOMAGEN0013, propertyName, className, e);
7791
}
7892
}
93+
94+
public static Class<?> forName(String className, String propertyName, ClassLoader classLoader) {
95+
AssertionUtil.assertNotNull(className, propertyName, classLoader);
96+
try {
97+
return classLoader.loadClass(className);
98+
} catch (ClassNotFoundException e) {
99+
throw new CodeGenException(Message.DOMAGEN0033, propertyName, className, e);
100+
}
101+
}
79102
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package org.seasar.doma.gradle.codegen.util;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
5+
import static org.junit.jupiter.api.Assertions.assertSame;
6+
import static org.junit.jupiter.api.Assertions.assertThrows;
7+
8+
import java.net.URL;
9+
import java.net.URLClassLoader;
10+
import java.util.ArrayList;
11+
import java.util.List;
12+
import org.junit.jupiter.api.Test;
13+
import org.seasar.doma.gradle.codegen.exception.CodeGenException;
14+
15+
@SuppressWarnings("unchecked")
16+
public class ClassUtilTest {
17+
18+
@Test
19+
public void testGetPackageName() {
20+
assertEquals("java.lang", ClassUtil.getPackageName("java.lang.String"));
21+
assertEquals("", ClassUtil.getPackageName("String"));
22+
assertEquals("", ClassUtil.getPackageName(""));
23+
}
24+
25+
@Test
26+
public void testGetSimpleName() {
27+
assertEquals("String", ClassUtil.getSimpleName("java.lang.String"));
28+
assertEquals("String", ClassUtil.getSimpleName("String"));
29+
assertEquals("", ClassUtil.getSimpleName(""));
30+
}
31+
32+
@Test
33+
public void testToBoxedPrimitiveTypeIfPossible() {
34+
assertSame(Void.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(void.class));
35+
assertSame(Character.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(char.class));
36+
assertSame(Boolean.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(boolean.class));
37+
assertSame(Byte.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(byte.class));
38+
assertSame(Short.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(short.class));
39+
assertSame(Integer.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(int.class));
40+
assertSame(Long.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(long.class));
41+
assertSame(Float.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(float.class));
42+
assertSame(Double.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(double.class));
43+
assertSame(String.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(String.class));
44+
}
45+
46+
@Test
47+
public void testNewInstance() {
48+
List<String> list = ClassUtil.newInstance(List.class, "java.util.ArrayList", "testProperty");
49+
assertInstanceOf(ArrayList.class, list);
50+
}
51+
52+
@Test
53+
public void testNewInstance_WithClassLoader() throws Exception {
54+
URLClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader());
55+
List<String> list =
56+
ClassUtil.newInstance(List.class, "java.util.ArrayList", "testProperty", classLoader);
57+
assertInstanceOf(ArrayList.class, list);
58+
}
59+
60+
@Test
61+
public void testNewInstance_ClassNotFound() {
62+
assertThrows(
63+
CodeGenException.class,
64+
() -> {
65+
ClassUtil.newInstance(List.class, "non.existent.Class", "testProperty");
66+
});
67+
}
68+
69+
@Test
70+
public void testNewInstance_NotAssignable() {
71+
assertThrows(
72+
CodeGenException.class,
73+
() -> {
74+
ClassUtil.newInstance(List.class, "java.lang.String", "testProperty");
75+
});
76+
}
77+
78+
@Test
79+
public void testNewInstance_WithClassLoader_ClassNotFound() throws Exception {
80+
URLClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader());
81+
assertThrows(
82+
CodeGenException.class,
83+
() -> {
84+
ClassUtil.newInstance(List.class, "non.existent.Class", "testProperty", classLoader);
85+
});
86+
}
87+
88+
@Test
89+
public void testNewInstance_WithClassLoader_NotAssignable() throws Exception {
90+
try (URLClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader())) {
91+
assertThrows(
92+
CodeGenException.class,
93+
() -> {
94+
ClassUtil.newInstance(List.class, "java.lang.String", "testProperty", classLoader);
95+
});
96+
}
97+
}
98+
99+
@Test
100+
public void testForName() {
101+
Class<?> clazz = ClassUtil.forName("java.lang.String", "testProperty");
102+
assertSame(String.class, clazz);
103+
}
104+
105+
@Test
106+
public void testForName_WithClassLoader() throws Exception {
107+
URLClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader());
108+
Class<?> clazz = ClassUtil.forName("java.lang.String", "testProperty", classLoader);
109+
assertSame(String.class, clazz);
110+
}
111+
112+
@Test
113+
public void testForName_ClassNotFound() {
114+
assertThrows(
115+
CodeGenException.class,
116+
() -> {
117+
ClassUtil.forName("non.existent.Class", "testProperty");
118+
});
119+
}
120+
121+
@Test
122+
public void testForName_WithClassLoader_ClassNotFound() throws Exception {
123+
URLClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader());
124+
assertThrows(
125+
CodeGenException.class,
126+
() -> {
127+
ClassUtil.forName("non.existent.Class", "testProperty", classLoader);
128+
});
129+
}
130+
}

0 commit comments

Comments
 (0)