'Unable to connect IBMi machine with Spring Data & JPA
Trying connect IBMi machine by using Spring Data & JPA, but it's generating the error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [HibernateJpaConfiguration.class]: Bean instantiation via factory method failed;
nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean]: Factory method 'entityManagerFactory' threw exception; nested exception is java.lang.AbstractMethodError: Receiver class com.ibm.as400.access.AS400JDBCConnectionImpl does not define or inherit an implementation of the resolved method 'abstract boolean isValid(int)' of interface java.sql.Connection.
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:658) ~[spring-beans-5.3.8.jar:5.3.8]
at spring.security.as400.SpringSecurityDemoApplication2.main(SpringSecurityDemoApplication2.java:10) ~[classes/:na]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean]: Factory method 'entityManagerFactory' threw exception; nested exception is java.lang.AbstractMethodError: Receiver class com.ibm.as400.access.AS400JDBCConnectionImpl does not define or inherit an implementation of the resolved method 'abstract boolean isValid(int)' of interface java.sql.Connection.
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.3.8.jar:5.3.8]
Caused by: java.lang.AbstractMethodError: Receiver class com.ibm.as400.access.AS400JDBCConnectionImpl does not define or inherit an implementation of the resolved method 'abstract boolean isValid(int)' of interface java.sql.Connection.
at com.zaxxer.hikari.pool.PoolBase.checkValidationSupport(PoolBase.java:458) ~[HikariCP-3.4.5.jar:na]
The project is a starter project for learning Spring Data using JPA to connect with IBMi machine, but seems Spring Data doesn't provide the easiest way for this.
My Project classes are:
- 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.4.7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>Spring-Security-JT400</groupId>
<artifactId>Security-JT400</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Security-JT400</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>net.sf.jt400</groupId>
<artifactId>jt400</artifactId>
<version>10.6</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- Configuration
@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter
{
@Autowired
CustomUserDetailsService customUserDetailsService;
@Bean
AuthenticationProvider authenticationProvider()
{
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(customUserDetailsService);
provider.setPasswordEncoder(new BCryptPasswordEncoder());
return provider;
}
@Override
protected void configure(HttpSecurity http) throws Exception
{
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/home").hasAuthority("USER")
.antMatchers("/admin").hasAuthority("ADMIN")
.anyRequest().authenticated()
.and()
.httpBasic();
}
}
- CustomUserDetailsService
@Service
public class CustomUserDetailsService implements UserDetailsService
{
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
{
User user = userRepository.findByUsername(username);
if (user == null)
{
throw new UsernameNotFoundException("User not found.");
}
return new CustomUserDetails(user);
}
}
@Repository
public interface UserRepository extends JpaRepository<User, Integer>
{
public User findByUsername(String username);
}
@RestController
public class HomeController
{
@GetMapping("/home")
public String home()
{
return "This is Home Page.";
}
@GetMapping("/admin")
public String admin()
{
return "This is Admin Page.";
}
}
public class CustomUserDetails implements UserDetails
{
private User user;
public CustomUserDetails(User user)
{
super();
this.user = user;
}
private static final long serialVersionUID = -228521734196009612L;
@Override
public Collection<? extends GrantedAuthority> getAuthorities()
{
return Collections.singleton(new SimpleGrantedAuthority(user.getRole()));
}
@Override
public String getPassword()
{
return user.getPassword();
}
@Override
public String getUsername()
{
return user.getUsername();
}
@Override
public boolean isAccountNonExpired()
{
return true;
}
@Override
public boolean isAccountNonLocked()
{
return true;
}
@Override
public boolean isCredentialsNonExpired()
{
return true;
}
@Override
public boolean isEnabled()
{
return true;
}
}
@Entity
public class User
{
@Id
private int id;
private String username;
private String password;
private String role;
}
@SpringBootApplication
public class SpringSecurityDemoApplication2 {
public static void main(String[] args) {
SpringApplication.run(SpringSecurityDemoApplication2.class, args);
}
}
- application.properties
spring.datasource.url=jdbc:as400://192.168.xx.xxx/;translate binary=true;prompt=false
spring.datasource.username=USERNAME
spring.datasource.password=PASSWORD
spring.datasource.driver-class-name=com.ibm.as400.access.AS400JDBCDriver
spring.jpa.database-platform=org.hibernate.dialect.DB2400Dialect
Note: Using same classes and making changes in application.properties, able to connect with MYSQL database.
Solution 1:[1]
Try adding @EnableJpaRepositories annotation below the @SpringBootApplication
Solution 2:[2]
I had the same issue. The problem is that seems that the method abstract boolean isValid(int)
is not implemented, or doesn't work correctly (I'm not sure). Basically, it's checking if the connection to DB is healthy.
Happily, you can change it to your own. In spring boot just add to application.properties: spring.datasource.hikari.connection-test-query: values 1
For me values 1 worked (I'm using AS400 DB2), but for others DB you may need to use different ones check this answer
I had multiple Datasources and unfortunately adding them to application.properties was not enough, I had to set it in PersistanceConfigurator like this:
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource as400DataSource() {
HikariDataSource dataSource = (HikariDataSource) DataSourceBuilder.create().build();
dataSource.setConnectionTestQuery("values 1");
return dataSource;
}
Now it's working perfectly fine.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Saraswathi Kaluva |
Solution 2 | Jakub Jakubowski |