現在、GraalVM ネイティブ イメージ ツールを試しています。目標は、postgresql でスプリング ブート Web アプリケーションを実行することです。
私のプロジェクトは mvn clean パッケージでコンパイルされ、.JAR は docker-postgresql で魅力的に動作しますが、これからネイティブ イメージを構築することはできません。
Josh Long の Spring のヒントからこのきちんとしたコンパイル スクリプトを見つけました。これは、以前のプロジェクトの構成に大いに役立ちました。これまでのところ、StringIndexOutOfBoundsException をスローするだけなので、ネイティブ イメージがビルドされない理由がわかりません。h2とjpaを使用した別のプロジェクトがあり、まったく同じパラメーターでそれを行います。
構成またはエクスペリエンスと ofc ソリューションを変更する場所に関するいくつかの提案を期待しています。
現在、GraalVM バージョン 20.1.0 (Java バージョン 1.8.0_252) を JDK として使用しています。
以下は、スタックトレースとサンプル プロジェクトです。また、./compile.sh のターミナル出力をhttps://file.io/HXudRpH80dDzにアップロードしました。
Fatal error:java.lang.StringIndexOutOfBoundsException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:598)
at java.util.concurrent.ForkJoinTask.get(ForkJoinTask.java:1005)
at com.oracle.svm.hosted.NativeImageGenerator.run(NativeImageGenerator.java:463)
at com.oracle.svm.hosted.NativeImageGeneratorRunner.buildImage(NativeImageGeneratorRunner.java:359)
at com.oracle.svm.hosted.NativeImageGeneratorRunner.build(NativeImageGeneratorRunner.java:518)
at com.oracle.svm.hosted.NativeImageGeneratorRunner.main(NativeImageGeneratorRunner.java:117)
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at java.lang.String.substring(String.java:1967)
at org.springframework.graalvm.type.TypeSystem.resolve(TypeSystem.java:208)
at org.springframework.graalvm.type.Method.getReturnType(Method.java:199)
at org.springframework.graalvm.type.Type.collectAtMappingMarkedReturnTypes(Type.java:1655)
at org.springframework.graalvm.support.ResourcesHandler.processResponseBodyComponent(ResourcesHandler.java:428)
at org.springframework.graalvm.support.ResourcesHandler.processSpringComponents(ResourcesHandler.java:310)
at org.springframework.graalvm.support.ResourcesHandler.processExistingOrSynthesizedSpringComponentsFiles(ResourcesHandler.java:177)
at org.springframework.graalvm.support.ResourcesHandler.register(ResourcesHandler.java:124)
at org.springframework.graalvm.support.SpringFeature.beforeAnalysis(SpringFeature.java:78)
at com.oracle.svm.hosted.NativeImageGenerator.lambda$runPointsToAnalysis$7(NativeImageGenerator.java:679)
at com.oracle.svm.hosted.FeatureHandler.forEachFeature(FeatureHandler.java:70)
at com.oracle.svm.hosted.NativeImageGenerator.runPointsToAnalysis(NativeImageGenerator.java:679)
at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:538)
at com.oracle.svm.hosted.NativeImageGenerator.lambda$run$0(NativeImageGenerator.java:451)
at java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1386)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Error: Image build request failed with exit status 1
com.oracle.svm.driver.NativeImage$NativeImageError: Image build request failed with exit status 1
at com.oracle.svm.driver.NativeImage.showError(NativeImage.java:1541)
at com.oracle.svm.driver.NativeImage.build(NativeImage.java:1299)
at com.oracle.svm.driver.NativeImage.performBuild(NativeImage.java:1260)
at com.oracle.svm.driver.NativeImage.main(NativeImage.java:1219)
real 0m36,107s
user 1m0,314s
sys 0m2,100s
コンパイル.sh
#!/usr/bin/env bash
ARTIFACT=${1}
MAINCLASS=${2}
VERSION=${3}
JAR="${ARTIFACT}-${VERSION}.jar"
rm -rf target
mkdir -p target/native-image
mvn package
rm -f $ARTIFACT
cd target/native-image
jar -xvf ../$JAR
cp -R META-INF BOOT-INF/classes
LIBPATH=`find BOOT-INF/lib | tr '\n' ':'`
CP=BOOT-INF/classes:$LIBPATH
GRAALVM_VERSION=`native-image --version`
time native-image \
--verbose \
-H:EnableURLProtocols=http \
-H:+RemoveSaturatedTypeFlows \
-H:Name=$ARTIFACT \
-H:+TraceClassInitialization \
--initialize-at-build-time=org.springframework.util.unit.DataSize \
-H:+ReportExceptionStackTraces \
-Dspring.native.verbose=true \
-Dspring.native.remove-jmx-support=true \
-Dspring.native.remove-spel-support=true \
-Dspring.native.remove-yaml-support=true \
-cp $CP $MAINCLASS \
--no-fallback\
--allow-incomplete-classpath\
-Dspring.native.remove-xml-support=true
pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>postgres</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for postgresql native-image</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- -->
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-graalvm-native</artifactId>
<version>0.7.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-indexer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!--
<plugin>
<groupId>org.hibernate.orm.tooling</groupId>
<artifactId>hibernate-enhance-maven-plugin</artifactId>
<version>${hibernate.version}</version>
<executions>
<execution>
<configuration>
<failOnError>true</failOnError>
<enableLazyInitialization>true</enableLazyInitialization>
<enableDirtyTracking>true</enableDirtyTracking>
<enableExtendedEnhancement>false</enableExtendedEnhancement>
</configuration>
<goals>
<goal>enhance</goal>
</goals>
</execution>
</executions>
</plugin>
-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</pluginRepository>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
アプリケーションのプロパティ
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=none
spring.jpa.hibernate.show-sql=true
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=admin
spring.datasource.initialization-mode=always
spring.datasource.schema=classpath:/schema.sql
spring.datasource.continue-on-error=true
PostgresApplication.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration;
@SpringBootApplication(
exclude = SpringDataWebAutoConfiguration.class,
proxyBeanMethods = false
)
public class PostgresApplication {
public static void main(String[] args) {
SpringApplication.run(PostgresApplication.class, args);
}
}
従業員.java
public class Employee {
String employeeId;
String employeeName;
String employeeEmail;
String employeeAddress;
public String getEmployeeEmail() {
return employeeEmail;
}
public void setEmployeeEmail(String employeeEmail) {
this.employeeEmail = employeeEmail;
}
public String getEmployeeId() {
return employeeId;
}
public void setEmployeeId(String employeeId) {
this.employeeId = employeeId;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public String getEmployeeAddress() {
return employeeAddress;
}
public void setEmployeeAddress(String employeeAddress) {
this.employeeAddress = employeeAddress;
}}
EmployeeRowMapper.java
import java.sql.ResultSet;
import java.sql.SQLException;
import com.example.postgres.entity.Employee;
import org.springframework.jdbc.core.RowMapper;
public class EmployeeRowMapper implements RowMapper<Employee> {
@Override
public Employee mapRow(ResultSet rs, int arg1) throws SQLException {
Employee emp = new Employee();
emp.setEmployeeId(rs.getString("employeeId"));
emp.setEmployeeName(rs.getString("employeeName"));
emp.setEmployeeEmail(rs.getString("employeeEmail"));
emp.setEmployeeAddress(rs.getString("employeeAddress"));
return emp;
}
}
EmployeeDao.java
import com.example.postgres.entity.Employee;
import java.util.List;
public interface EmployeeDao {
List<Employee> findAll();
void insertEmployee(Employee emp);
void updateEmployee(Employee emp);
void executeUpdateEmployee(Employee emp);
public void deleteEmployee(Employee emp);
}
EmployeeDaoImpl.java
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.example.postgres.entity.Employee;
import com.example.postgres.mapper.EmployeeRowMapper;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
@Repository
public class EmployeeDaoImpl implements EmployeeDao{
public EmployeeDaoImpl(NamedParameterJdbcTemplate template) {
this.template = template;
}
NamedParameterJdbcTemplate template;
@Override
public List<Employee> findAll() {
return template.query("select * from employee", new EmployeeRowMapper());
}
@Override
public void insertEmployee(Employee emp) {
final String sql = "insert into employee(employeeId, employeeName , employeeAddress,employeeEmail) values(:employeeId,:employeeName,:employeeEmail,:employeeAddress)";
KeyHolder holder = new GeneratedKeyHolder();
SqlParameterSource param = new MapSqlParameterSource()
.addValue("employeeId", emp.getEmployeeId())
.addValue("employeeName", emp.getEmployeeName())
.addValue("employeeEmail", emp.getEmployeeEmail())
.addValue("employeeAddress", emp.getEmployeeAddress());
template.update(sql,param, holder);
}
@Override
public void updateEmployee(Employee emp) {
final String sql = "update employee set employeeName=:employeeName, employeeAddress=:employeeAddress, employeeEmail=:employeeEmail where employeeId=:employeeId";
KeyHolder holder = new GeneratedKeyHolder();
SqlParameterSource param = new MapSqlParameterSource()
.addValue("employeeId", emp.getEmployeeId())
.addValue("employeeName", emp.getEmployeeName())
.addValue("employeeEmail", emp.getEmployeeEmail())
.addValue("employeeAddress", emp.getEmployeeAddress());
template.update(sql,param, holder);
}
@Override
public void executeUpdateEmployee(Employee emp) {
final String sql = "update employee set employeeName=:employeeName, employeeAddress=:employeeAddress, employeeEmail=:employeeEmail where employeeId=:employeeId";
Map<String,Object> map=new HashMap<String,Object>();
map.put("employeeId", emp.getEmployeeId());
map.put("employeeName", emp.getEmployeeName());
map.put("employeeEmail", emp.getEmployeeEmail());
map.put("employeeAddress", emp.getEmployeeAddress());
template.execute(sql,map,new PreparedStatementCallback<Object>() {
@Override
public Object doInPreparedStatement(PreparedStatement ps)
throws SQLException, DataAccessException {
return ps.executeUpdate();
}
});
}
@Override
public void deleteEmployee(Employee emp) {
final String sql = "delete from employee where employeeId=:employeeId";
Map<String,Object> map=new HashMap<String,Object>();
map.put("employeeId", emp.getEmployeeId());
template.execute(sql,map,new PreparedStatementCallback<Object>() {
@Override
public Object doInPreparedStatement(PreparedStatement ps)
throws SQLException, DataAccessException {
return ps.executeUpdate();
}
});
}
}
EmployeeService.java
import java.util.List;
import com.example.postgres.entity.Employee;
public interface EmployeeService {
List<Employee> findAll();
void insertEmployee(Employee emp);
void updateEmployee(Employee emp);
void executeUpdateEmployee(Employee emp);
void deleteEmployee(Employee emp);
}
EmployeeServiceImpl.java
import javax.annotation.Resource;
import java.util.List;
import com.example.postgres.dao.EmployeeDao;
import com.example.postgres.entity.Employee;
import org.springframework.stereotype.Component;
@Component
public class EmployeeServiceImpl implements EmployeeService{
@Resource
EmployeeDao employeeDao;
@Override
public List<Employee> findAll() {
return employeeDao.findAll();
}
@Override
public void insertEmployee(Employee emp) {
employeeDao.insertEmployee(emp);
}
@Override
public void updateEmployee(Employee emp) {
employeeDao.updateEmployee(emp);
}
@Override
public void executeUpdateEmployee(Employee emp) {
employeeDao.executeUpdateEmployee(emp);
}
@Override
public void deleteEmployee(Employee emp) {
employeeDao.deleteEmployee(emp);
}
}
ApplicationController.java
import java.util.List;
import javax.annotation.Resource;
import com.example.postgres.entity.Employee;
import com.example.postgres.service.EmployeeService;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/postgresApp")
public class ApplicationController {
@Resource
EmployeeService employeeService;
@GetMapping(value = "/employeeList")
public List<Employee> getEmployees() {
return employeeService.findAll();
}
@PostMapping(value = "/createEmp")
public void createEmployee(@RequestBody Employee emp) {
employeeService.insertEmployee(emp);
}
@PutMapping(value = "/updateEmp")
public void updateEmployee(@RequestBody Employee emp) {
employeeService.updateEmployee(emp);
}
@PutMapping(value = "/executeUpdateEmp")
public void executeUpdateEmployee(@RequestBody Employee emp) {
employeeService.executeUpdateEmployee(emp);
}
@DeleteMapping(value = "/deleteEmpById")
public void deleteEmployee(@RequestBody Employee emp) {
employeeService.deleteEmployee(emp);
}
}