'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:

  1. 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>
  1. 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();
        }
    }
  1. 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);
        }
    }
  1. 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