Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 17 additions & 22 deletions codegen-test/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import org.h2.Driver
import org.seasar.doma.gradle.codegen.desc.LanguageType
import org.seasar.doma.gradle.codegen.jdbc.SimpleDataSource

buildscript {
repositories {
Expand All @@ -11,10 +9,7 @@ buildscript {
}
}
dependencies {
val h2Version: String = properties["h2Version"] as String
classpath("org.domaframework.doma:codegen")
classpath("com.h2database:h2:$h2Version")
classpath("mysql:mysql-connector-java:8.0.33")
}
}

Expand All @@ -23,6 +18,7 @@ plugins {
id("org.jetbrains.kotlin.jvm") version "2.2.0"
id("org.domaframework.doma.compile") version "4.0.0"
id("org.domaframework.doma.codegen")
id("com.nocwriter.runsql") version "1.0.3"
}

java {
Expand All @@ -40,13 +36,19 @@ dependencies {

implementation("org.seasar.doma:doma-core:$domaVersion")
annotationProcessor("org.seasar.doma:doma-processor:$domaVersion")

// Use JUnit BOM for version management
testImplementation(platform("org.junit:junit-bom:5.13.2"))
testImplementation("org.junit.jupiter:junit-jupiter-api")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
testRuntimeOnly("com.h2database:h2:$h2Version")

// Add H2 to the domaCodeGen configuration
domaCodeGen("com.h2database:h2:$h2Version")

// Used by runsql-gradle-plugin
runtimeOnly("com.h2database:h2:$h2Version")
}

val _url = "jdbc:h2:file:$projectDir/data/db"
Expand Down Expand Up @@ -92,15 +94,13 @@ tasks {
}
}

val createDb = register("createDb") {
doLast {
val ds = SimpleDataSource()
ds.setDriver(Driver())
ds.setUrl(_url)
ds.setUser(_user)
ds.setPassword(_password)

val sql = """
val createDb = register<RunSQL>("createDb") {
config {
username = _user
password = _password
url = _url
driverClassName = "org.h2.Driver"
script = """
drop all objects;

create table department(
Expand All @@ -115,13 +115,8 @@ tasks {
employee_id integer not null primary key,
employee_no integer not null,
employee_name varchar(20)
);
"""
ds.connection.use {
it.createStatement().use {
it.execute(sql)
}
}
);
""".trimIndent()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
public class CodeGenPlugin implements Plugin<Project> {

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

@Override
public void apply(Project project) {
project
.getConfigurations()
.create(
CONFIGURATION_NAME,
config -> {
config.setDescription(
"The libraries used by the Doma CodeGen plugin for JDBC drivers and other dependencies");
config.setVisible(false);
config.setCanBeConsumed(false);
config.setCanBeResolved(true);
});

NamedDomainObjectContainer<CodeGenConfig> container =
project.container(
CodeGenConfig.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
package org.seasar.doma.gradle.codegen.extension;

import static org.seasar.doma.gradle.codegen.CodeGenPlugin.CONFIGURATION_NAME;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.sql.Driver;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import javax.sql.DataSource;
import org.gradle.api.Action;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.file.Directory;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileTree;
Expand All @@ -31,6 +37,8 @@ public class CodeGenConfig {

private final String name;

private final Configuration configuration;

private final Property<GlobalFactory> globalFactory;

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

this.configuration = project.getConfigurations().getByName(CONFIGURATION_NAME);

ObjectFactory objects = project.getObjects();

globalFactory = objects.property(GlobalFactory.class);
Expand Down Expand Up @@ -146,13 +156,32 @@ private Provider<DataSource> dataSourceProvider() {
if (driverClassName == null) {
throw new CodeGenException(Message.DOMAGEN0024);
}
Driver driver = ClassUtil.newInstance(Driver.class, driverClassName, "driverClassName");
ClassLoader classLoader = createClassLoader();
Driver driver =
ClassUtil.newInstance(Driver.class, driverClassName, "driverClassName", classLoader);
return globalFactory
.get()
.createDataSource(driver, user.getOrNull(), password.getOrNull(), url.get());
});
}

protected ClassLoader createClassLoader() {
if (configuration == null || configuration.isEmpty()) {
return getClass().getClassLoader();
}
Set<File> fileSet = configuration.getFiles();
URL[] urls = new URL[fileSet.size()];
int i = 0;
for (File file : fileSet) {
try {
urls[i++] = file.toURI().toURL();
} catch (Exception e) {
throw new RuntimeException("Failed to convert file to URL: " + file, e);
}
}
return new URLClassLoader(urls, getClass().getClassLoader());
}

private Provider<CodeGenDialect> codeGenDialectProvider() {
return url.map(
it -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ public enum Message implements MessageResource {
"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."),
DOMAGEN0025(
"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."),
DOMAGEN0033("The class \"{1}\" to which the parameter \"{0}\" refers is not found. {2}"),
DOMAGEN0034(
"The class \"{1}\" to which the parameter \"{0}\" refers must be a subtype of the class \"{2}\"."),
DOMAGEN0035(
"The class \"{1}\" to which the parameter \"{0}\" refers cannot be instantiated. The class \"{1}\" must have a public default constructor. {2}"),

DOMAGEN5001(
"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\")"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,20 @@ public static <T> T newInstance(Class<T> supertype, String className, String pro
}
}

public static <T> T newInstance(
Class<T> supertype, String className, String propertyName, ClassLoader classLoader) {
AssertionUtil.assertNotNull(supertype, className, propertyName, classLoader);
Class<?> clazz = forName(className, propertyName, classLoader);
if (!supertype.isAssignableFrom(clazz)) {
throw new CodeGenException(Message.DOMAGEN0034, propertyName, className, supertype.getName());
}
try {
return supertype.cast(clazz.getDeclaredConstructor().newInstance());
} catch (ReflectiveOperationException e) {
throw new CodeGenException(Message.DOMAGEN0035, propertyName, className, e);
}
}

public static Class<?> forName(String className, String propertyName) {
AssertionUtil.assertNotNull(className, propertyName);
try {
Expand All @@ -76,4 +90,13 @@ public static Class<?> forName(String className, String propertyName) {
throw new CodeGenException(Message.DOMAGEN0013, propertyName, className, e);
}
}

public static Class<?> forName(String className, String propertyName, ClassLoader classLoader) {
AssertionUtil.assertNotNull(className, propertyName, classLoader);
try {
return classLoader.loadClass(className);
} catch (ClassNotFoundException e) {
throw new CodeGenException(Message.DOMAGEN0033, propertyName, className, e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package org.seasar.doma.gradle.codegen.util;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.seasar.doma.gradle.codegen.exception.CodeGenException;

@SuppressWarnings("unchecked")
public class ClassUtilTest {

@Test
public void testGetPackageName() {
assertEquals("java.lang", ClassUtil.getPackageName("java.lang.String"));
assertEquals("", ClassUtil.getPackageName("String"));
assertEquals("", ClassUtil.getPackageName(""));
}

@Test
public void testGetSimpleName() {
assertEquals("String", ClassUtil.getSimpleName("java.lang.String"));
assertEquals("String", ClassUtil.getSimpleName("String"));
assertEquals("", ClassUtil.getSimpleName(""));
}

@Test
public void testToBoxedPrimitiveTypeIfPossible() {
assertSame(Void.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(void.class));
assertSame(Character.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(char.class));
assertSame(Boolean.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(boolean.class));
assertSame(Byte.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(byte.class));
assertSame(Short.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(short.class));
assertSame(Integer.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(int.class));
assertSame(Long.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(long.class));
assertSame(Float.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(float.class));
assertSame(Double.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(double.class));
assertSame(String.class, ClassUtil.toBoxedPrimitiveTypeIfPossible(String.class));
}

@Test
public void testNewInstance() {
List<String> list = ClassUtil.newInstance(List.class, "java.util.ArrayList", "testProperty");
assertInstanceOf(ArrayList.class, list);
}

@Test
public void testNewInstance_WithClassLoader() throws Exception {
URLClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader());
List<String> list =
ClassUtil.newInstance(List.class, "java.util.ArrayList", "testProperty", classLoader);
assertInstanceOf(ArrayList.class, list);
}

@Test
public void testNewInstance_ClassNotFound() {
assertThrows(
CodeGenException.class,
() -> {
ClassUtil.newInstance(List.class, "non.existent.Class", "testProperty");
});
}

@Test
public void testNewInstance_NotAssignable() {
assertThrows(
CodeGenException.class,
() -> {
ClassUtil.newInstance(List.class, "java.lang.String", "testProperty");
});
}

@Test
public void testNewInstance_WithClassLoader_ClassNotFound() throws Exception {
URLClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader());
assertThrows(
CodeGenException.class,
() -> {
ClassUtil.newInstance(List.class, "non.existent.Class", "testProperty", classLoader);
});
}

@Test
public void testNewInstance_WithClassLoader_NotAssignable() throws Exception {
try (URLClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader())) {
assertThrows(
CodeGenException.class,
() -> {
ClassUtil.newInstance(List.class, "java.lang.String", "testProperty", classLoader);
});
}
}

@Test
public void testForName() {
Class<?> clazz = ClassUtil.forName("java.lang.String", "testProperty");
assertSame(String.class, clazz);
}

@Test
public void testForName_WithClassLoader() throws Exception {
URLClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader());
Class<?> clazz = ClassUtil.forName("java.lang.String", "testProperty", classLoader);
assertSame(String.class, clazz);
}

@Test
public void testForName_ClassNotFound() {
assertThrows(
CodeGenException.class,
() -> {
ClassUtil.forName("non.existent.Class", "testProperty");
});
}

@Test
public void testForName_WithClassLoader_ClassNotFound() throws Exception {
URLClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader());
assertThrows(
CodeGenException.class,
() -> {
ClassUtil.forName("non.existent.Class", "testProperty", classLoader);
});
}
}