Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Required class information missing after upgrade to version higher than 42.2.14 #2008

Closed
okarmusk opened this issue Jan 2, 2021 · 33 comments

Comments

@okarmusk
Copy link

okarmusk commented Jan 2, 2021

I've upgraded driver to version 42.2.18, then Required class information missing error appeared. Source code with traces bellow. To omit error i had to back to version 42.2.14.

persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
  <persistence-unit name="valuation" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

    <class>com.example.model.Data</class>

    <properties>
      <!-- Configuring JDBC properties -->
      <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://url:5432/db"/>
      <property name="javax.persistence.jdbc.user" value="dbadmin"/>
      <property name="javax.persistence.jdbc.password" value="xyz"/>
      <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/>

      <!-- Hibernate properties -->
      <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL95Dialect"/>
      <property name="hibernate.hbm2ddl.auto" value="update"/>
      <property name="hibernate.format_sql" value="true"/>
      <property name="hibernate.show_sql" value="false"/>

      <!-- batching size -->
      <property name="hibernate.connection.autocommit" value="false"/>
      <property name="hibernate.jdbc.batch_size" value="30"/>
      <property name="hibernate.order_inserts" value="true"/>
      <property name="hibernate.order_updates" value="true"/>
      <property name="hibernate.jdbc.batch_versioned_data" value="true"/>
    </properties>
  </persistence-unit>
</persistence>

Stack trace:

Caused by: java.lang.IllegalStateException: Required class information is missing
	at org.jboss.jandex.Indexer.rebuildNestedType(Indexer.java:926)
	at org.jboss.jandex.Indexer.resolveTypePath(Indexer.java:786)
	at org.jboss.jandex.Indexer.resolveTypeAnnotation(Indexer.java:705)
	at org.jboss.jandex.Indexer.resolveTypeAnnotations(Indexer.java:613)
	at org.jboss.jandex.Indexer.index(Indexer.java:1602)
	at org.hibernate.boot.archive.scan.spi.ClassFileArchiveEntryHandler.toClassDescriptor(ClassFileArchiveEntryHandler.java:64)
	at org.hibernate.boot.archive.scan.spi.ClassFileArchiveEntryHandler.handleEntry(ClassFileArchiveEntryHandler.java:52)
	at org.hibernate.boot.archive.internal.JarFileBasedArchiveDescriptor.visitArchive(JarFileBasedArchiveDescriptor.java:147)
	at org.hibernate.boot.archive.scan.spi.AbstractScannerImpl.scan(AbstractScannerImpl.java:48)
	at org.hibernate.boot.model.process.internal.ScanningCoordinator.coordinateScan(ScanningCoordinator.java:76)
	at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.prepare(MetadataBuildingProcess.java:107)
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.<init>(EntityManagerFactoryBuilderImpl.java:254)
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.<init>(EntityManagerFactoryBuilderImpl.java:175)
	at org.hibernate.jpa.boot.spi.Bootstrap.getEntityManagerFactoryBuilder(Bootstrap.java:76)
	at org.hibernate.jpa.HibernatePersistenceProvider.getEntityManagerFactoryBuilder(HibernatePersistenceProvider.java:171)
	at org.hibernate.jpa.HibernatePersistenceProvider.getEntityManagerFactoryBuilderOrNull(HibernatePersistenceProvider.java:119)
	at org.hibernate.jpa.HibernatePersistenceProvider.getEntityManagerFactoryBuilderOrNull(HibernatePersistenceProvider.java:61)
	at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:50)
	at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
	at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
	at com.okarmusk.data.converter.persistence.dao.EntityManagerProvider.<clinit>(EntityManagerProvider.java:11)

@davecramer
Copy link
Member

So do we know what is causing this error ? What information is required ?

@okarmusk
Copy link
Author

okarmusk commented Jan 2, 2021

This stack trace is only one information what i received. People on stackoverflow already know issue, here is the link: stackoverflow issue

Issue is at least strength cause configuration lunched on newest Hibernate versions with pgjdbc version lower or equal to 42.2.14 works. Only if i changed pgjdbc driver version it failed, no metter of Hibernate version.

@davecramer
Copy link
Member

I created https://github.com/davecramer/hibernate_test and this works fine. If you can provide me with a small test code that fails that will help

@okarmusk
Copy link
Author

okarmusk commented Jan 2, 2021

First difference what i noticed is that i'm using import javax.persistence.* for JPA annotations, in your code there are:

import org.hibernate.annotations.Table;
import org.hibernate.annotations.Entity;
import org.hibernate.annotations.GenericGenerator;

Maybe if i use hibernate as a JPA provider i need to define something additional in persistence.xml what hibernate annotation contains by default...

@davecramer
Copy link
Member

Please provide me with code that breaks.

@okarmusk
Copy link
Author

okarmusk commented Jan 2, 2021

Here is additional stack trace:

Exception in thread "main" java.lang.ExceptionInInitializerError
	at com.okarmusk.messenger.dao.CurrencyQuotationDAO.<init>(CurrencyQuotationDAO.java:16)
	at com.okarmusk.messenger.services.CurrencyQuotationService.<init>(CurrencyQuotationService.java:17)
	at com.okarmusk.messenger.services.ForexNotificationService.<init>(ForexNotificationService.java:28)
	at com.okarmusk.messenger.Main.main(Main.java:14)
Caused by: java.lang.IllegalStateException: Required class information is missing
	at org.jboss.jandex.Indexer.rebuildNestedType(Indexer.java:926)
	at org.jboss.jandex.Indexer.resolveTypePath(Indexer.java:786)
	at org.jboss.jandex.Indexer.resolveTypeAnnotation(Indexer.java:705)
	at org.jboss.jandex.Indexer.resolveTypeAnnotations(Indexer.java:613)
	at org.jboss.jandex.Indexer.index(Indexer.java:1602)
	at org.hibernate.boot.archive.scan.spi.ClassFileArchiveEntryHandler.toClassDescriptor(ClassFileArchiveEntryHandler.java:64)
	at org.hibernate.boot.archive.scan.spi.ClassFileArchiveEntryHandler.handleEntry(ClassFileArchiveEntryHandler.java:52)
	at org.hibernate.boot.archive.internal.JarFileBasedArchiveDescriptor.visitArchive(JarFileBasedArchiveDescriptor.java:147)
	at org.hibernate.boot.archive.scan.spi.AbstractScannerImpl.scan(AbstractScannerImpl.java:48)
	at org.hibernate.boot.model.process.internal.ScanningCoordinator.coordinateScan(ScanningCoordinator.java:76)
	at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.prepare(MetadataBuildingProcess.java:107)
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.<init>(EntityManagerFactoryBuilderImpl.java:254)
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.<init>(EntityManagerFactoryBuilderImpl.java:175)
	at org.hibernate.jpa.boot.spi.Bootstrap.getEntityManagerFactoryBuilder(Bootstrap.java:76)
	at org.hibernate.jpa.HibernatePersistenceProvider.getEntityManagerFactoryBuilder(HibernatePersistenceProvider.java:171)
	at org.hibernate.jpa.HibernatePersistenceProvider.getEntityManagerFactoryBuilderOrNull(HibernatePersistenceProvider.java:119)
	at org.hibernate.jpa.HibernatePersistenceProvider.getEntityManagerFactoryBuilderOrNull(HibernatePersistenceProvider.java:61)
	at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:50)
	at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
	at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
	at com.okarmusk.messenger.dao.EntityManagerProvider.<clinit>(EntityManagerProvider.java:11)

Failing entity (database view):

package com.okarmusk.messenger.model;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import javax.persistence.*;
import java.io.Serializable;
import java.sql.Date;

@Entity
@Table(name = "currency_quotation")
public class CurrencyQuotation implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "exchange_rate_id")
    private int exchangeRateId;
    @Column(name = "from_currency_symbol")
    private String fromCurrencySymbol;
    @Column(name = "to_currency_symbol")
    private String toCurrencySymbol;
    @Column(name = "rate")
    private float rate;
    @Column(name = "quotation_date")
    private Date quotationDate;

    public CurrencyQuotation() {}

    public CurrencyQuotation(String fromCurrencySymbol, String toCurrencySymbol, float rate, Date quotationDate) {
        this.fromCurrencySymbol = fromCurrencySymbol;
        this.toCurrencySymbol = toCurrencySymbol;
        this.rate = rate;
        this.quotationDate = quotationDate;
    }

    public int getExchangeRateId() {
        return exchangeRateId;
    }

    public void setExchangeRateId(int exchangeRateId) {
        this.exchangeRateId = exchangeRateId;
    }

    public String getFromCurrencySymbol() {
        return fromCurrencySymbol;
    }

    public void setFromCurrencySymbol(String fromCurrencySymbol) {
        this.fromCurrencySymbol = fromCurrencySymbol;
    }

    public String getToCurrencySymbol() {
        return toCurrencySymbol;
    }

    public void setToCurrencySymbol(String toCurrencySymbol) {
        this.toCurrencySymbol = toCurrencySymbol;
    }

    public float getRate() {
        return rate;
    }

    public void setRate(float rate) {
        this.rate = rate;
    }

    public Date getQuotationDate() {
        return quotationDate;
    }

    public void setQuotationDate(Date quotationDate) {
        this.quotationDate = quotationDate;
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
    }
}

The DAO class:

package com.okarmusk.messenger.dao;

import com.okarmusk.messenger.model.CurrencyQuotation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import java.util.Optional;

public class CurrencyQuotationDAO {
    private final static Logger logger = LoggerFactory.getLogger(CurrencyQuotationDAO.class);
    private final EntityManager entityManager;

    public CurrencyQuotationDAO() {
        this(EntityManagerProvider.getEntityManager());
    }

    CurrencyQuotationDAO(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public Optional<CurrencyQuotation> getLastQuotation(final String fromSymbol, final String toSymbol) {
        try {
            final var query = "from CurrencyQuotation where fromCurrencySymbol=:fromSymbol and toCurrencySymbol=:toSymbol order by quotationDate desc";
            final var currencyValuation = entityManager.createQuery(query, CurrencyQuotation.class)
                    .setParameter("fromSymbol", fromSymbol)
                    .setParameter("toSymbol", toSymbol)
                    .setMaxResults(1).getSingleResult();

            return Optional.of(currencyValuation);
        } catch(NoResultException e) {
            logger.warn("Cannot find currency quotation for: {}:{}", fromSymbol, toSymbol);

            return Optional.empty();
        }
    }
}

Previous persistence.xml contains mock Data class. Right class tag in persistence.xml looks like:
<class>com.okarmusk.messenger.model.CurrencyQuotation</class>
Services CurrencyQuotationService and ForexNotificationService are only middle ware services.

EntityManagerProvider contains nothing special, but in case of need:

package com.okarmusk.messenger.dao;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class EntityManagerProvider {
    private final static EntityManagerFactory emf = Persistence.createEntityManagerFactory("valuation");
    private static final ThreadLocal<EntityManager> threadLocal = new ThreadLocal<>();
    private static final Logger logger = LogManager.getLogger(EntityManagerProvider.class);

    public static EntityManager getEntityManager() {
        var entityManager = threadLocal.get();

        if (entityManager == null) {
            synchronized (EntityManagerProvider.class) {
                entityManager = emf.createEntityManager();
                logger.info("EntityManager created");

                return entityManager;
            }
        }

        logger.debug("Getting EntityManager");

        return entityManager;
    }
}

@davecramer
Copy link
Member

What version of hibernate are you using ?

@okarmusk
Copy link
Author

okarmusk commented Jan 2, 2021

5.4.27.Final for core and entitymanager. i tried different hibernate versions, basically i've checked it since 5.4.23.Final.

@davecramer
Copy link
Member

Can you take my code and make it fail by changing the annotations ?

@vlsi
Copy link
Member

vlsi commented Jan 2, 2021

Here's a relevant jandex issue: smallrye/jandex#92

@okarmusk
Copy link
Author

okarmusk commented Jan 2, 2021

I have no access to write to repository. Can you add me?

Btw, when i ran your code from master in intellij it works. Problems started for compiling stuff manually and run it by command.
What i changed to reproduce issue:
First i changed Data.java to:

package org.postgresql.model;

import javax.persistence.*;

@Entity
@Table(name = "data")
public class Data {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id=id;
    }
}

Next i change build.gradle to:

plugins {
    id 'java'
}

group 'org.postgresql'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'org.hibernate', name:'hibernate-core', version: '5.4.25.Final'
    compile group: 'org.postgresql', name: 'postgresql', version: '42.2.18'
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

jar {
    manifest {
        attributes(
                'Class-Path': configurations.compile.collect { it.getName() }.join(' '),
                'Main-Class': 'org.postgresql.Test'
        )
    }
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}

Other lines without change. i run code by java -jar build/libs/hibernate_test-1.0-SNAPSHOT.jar.
Stack trace:

Jan 02, 2021 4:27:27 PM org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation
INFO: HHH000204: Processing PersistenceUnitInfo [name: valuation]
Jan 02, 2021 4:27:27 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate ORM core version [WORKING]
Jan 02, 2021 4:27:27 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
Exception in thread "main" java.lang.IllegalStateException: Required class information is missing
	at org.jboss.jandex.Indexer.rebuildNestedType(Indexer.java:926)
	at org.jboss.jandex.Indexer.resolveTypePath(Indexer.java:786)
	at org.jboss.jandex.Indexer.resolveTypeAnnotation(Indexer.java:705)
	at org.jboss.jandex.Indexer.resolveTypeAnnotations(Indexer.java:613)
	at org.jboss.jandex.Indexer.index(Indexer.java:1602)
	at org.hibernate.boot.archive.scan.spi.ClassFileArchiveEntryHandler.toClassDescriptor(ClassFileArchiveEntryHandler.java:64)
	at org.hibernate.boot.archive.scan.spi.ClassFileArchiveEntryHandler.handleEntry(ClassFileArchiveEntryHandler.java:52)
	at org.hibernate.boot.archive.internal.JarFileBasedArchiveDescriptor.visitArchive(JarFileBasedArchiveDescriptor.java:147)
	at org.hibernate.boot.archive.scan.spi.AbstractScannerImpl.scan(AbstractScannerImpl.java:48)
	at org.hibernate.boot.model.process.internal.ScanningCoordinator.coordinateScan(ScanningCoordinator.java:76)
	at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.prepare(MetadataBuildingProcess.java:107)
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.<init>(EntityManagerFactoryBuilderImpl.java:254)
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.<init>(EntityManagerFactoryBuilderImpl.java:175)
	at org.hibernate.jpa.boot.spi.Bootstrap.getEntityManagerFactoryBuilder(Bootstrap.java:76)
	at org.hibernate.jpa.HibernatePersistenceProvider.getEntityManagerFactoryBuilder(HibernatePersistenceProvider.java:171)
	at org.hibernate.jpa.HibernatePersistenceProvider.getEntityManagerFactoryBuilderOrNull(HibernatePersistenceProvider.java:119)
	at org.hibernate.jpa.HibernatePersistenceProvider.getEntityManagerFactoryBuilderOrNull(HibernatePersistenceProvider.java:61)
	at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:50)
	at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
	at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
	at org.postgresql.Test.main(Test.java:9)

@davecramer
Copy link
Member

When I run it I get

java.lang.NoClassDefFoundError: javax/persistence/Persistence
	at org.postgresql.Test.main(Test.java:9)
Caused by: java.lang.ClassNotFoundException: javax.persistence.Persistence
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)

I presume you have a classpath setup.

When I run this from inside intellij it runs fine.

@okarmusk
Copy link
Author

okarmusk commented Jan 2, 2021

I get the same error if i used implementation instead of compile in build.gradle. Did you changed it?
Class-Path was also defined in jar {...} section in build.gradle.

@davecramer
Copy link
Member

I did and can replicate the error now. Interestingly if I run it inside intellij it works fine. If I run it outside it does not.

The type it is trying to find the path to is

private final Provider timeZoneProvider;

Strangely it is looking it up as a NESTED instead of PARAMATERIZED

The annotation it is looking for is @nullable which I can't find anywhere.

Looks like Provider was added in 1e1f3c4 which is likely the reason.

@vlsi
Copy link
Member

vlsi commented Jan 2, 2021

There are two types of possibilities of the bugs:

a) javac bugs. Old (e.g. pre 1.8u202) had several known bugs that caused javac to produce invalid bytecode
b) org.jboss:jandex bugs when parsing class files with type annotations

If I rebuild pgjdbc with Java 11 (just in case), and add compile 'org.jboss:jandex:2.2.2.Final', the error becomes

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1
	at org.jboss.jandex.Indexer.updateTypeTarget(Indexer.java:847)
	at org.jboss.jandex.Indexer.updateTypeTargets(Indexer.java:630)
	at org.jboss.jandex.Indexer.index(Indexer.java:1618)
	at org.hibernate.boot.archive.scan.spi.ClassFileArchiveEntryHandler.toClassDescriptor(ClassFileArchiveEntryHandler.java:64)
	at org.hibernate.boot.archive.scan.spi.ClassFileArchiveEntryHandler.handleEntry(ClassFileArchiveEntryHandler.java:52)
	at org.hibernate.boot.archive.internal.JarFileBasedArchiveDescriptor.visitArchive(JarFileBasedArchiveDescriptor.java:147)
	at org.hibernate.boot.archive.scan.spi.AbstractScannerImpl.scan(AbstractScannerImpl.java:48)

@davecramer
Copy link
Member

Interestingly in my email what I see your error becoming is:

Exception in thread "main" java.lang.IllegalStateException: Required class information is missing
	at org.jboss.jandex.Indexer.rebuildNestedType(Indexer.java:932)
	at org.jboss.jandex.Indexer.resolveTypePath(Indexer.java:792)
	at org.jboss.jandex.Indexer.resolveTypeAnnotation(Indexer.java:711)
	at org.jboss.jandex.Indexer.resolveTypeAnnotations(Indexer.java:619)
	at org.jboss.jandex.Indexer.index(Indexer.java:1617)
	at org.hibernate.boot.archive.scan.spi.ClassFileArchiveEntryHandler.toClassDescriptor(ClassFileArchiveEntryHandler.java:64)

@vlsi
Copy link
Member

vlsi commented Jan 3, 2021

public class LruCache<Key extends @NonNull Object, Value extends @NonNull CanEstimateSize>
    implements Gettable<Key, Value> {

javap -verbose -p LruCache.class

Signature: #116                         // <Key:Ljava/lang/Object;Value::Lorg/postgresql/util/CanEstimateSize;>Ljava/lang/Object;Lorg/postgresql/util/Gettable<TKey;TValue;>;
SourceFile: "LruCache.java"
RuntimeVisibleTypeAnnotations:
  0: #119(): CLASS_TYPE_PARAMETER_BOUND, param_index=0, bound_index=0
    org.checkerframework.checker.nullness.qual.NonNull
  1: #119(): CLASS_TYPE_PARAMETER_BOUND, param_index=1, bound_index=1
    org.checkerframework.checker.nullness.qual.NonNull

This represents the two @NonNull annotations.

Unfortunately, it is not clear which specification declares that optional class bound should reserve "bound_index=0", however, OpenJDK implementation does adjust the index.
Interestingly enough, there was a recent fix in the area of reflection vs type annotations: openjdk/jdk@9d7f8bc

@vlsi
Copy link
Member

vlsi commented Jan 3, 2021

Just in case, Value::Lorg/postgresql/util/CanEstimateSize; in the signature attribute means something like Value extends Object & CanEstimateSize, so bound_index=1 means that the annotation is placed at CanEstimateSize rather than at Object.

It looks like jandex does not handle that :-(

@davecramer
Copy link
Member

So at this point my recommendation would be not to use the JPA annotations.

@vlsi
Copy link
Member

vlsi commented Jan 3, 2021

I've created jandex issue: smallrye/jandex#99

The takeaway for pgjdbc is we might want to verify that the produced bytecode is parseable with jandex, asm, and probably other bytecode analysis frameworks.

@bokken
Copy link
Member

bokken commented Jan 3, 2021 via email

@okarmusk
Copy link
Author

@vlsi i guess fix has been merged, when next release is planned? If code is merged should i close the issue, or should i wait till next release and verify if it works?

@vlsi
Copy link
Member

vlsi commented Jan 10, 2021

@okarmusk , do you think you could verify if #2010 solves the issue for you?

I wanted to add Java 11 test with Jandex (as javac 11 produces slightly different java8 bytecode), however, it turned out Java11+ and PostgreSQL12+ have issues with SSL client certificates which I am analyzing at the moment.

@hiroSzymon
Copy link

When I run it I get

java.lang.NoClassDefFoundError: javax/persistence/Persistence
	at org.postgresql.Test.main(Test.java:9)
Caused by: java.lang.ClassNotFoundException: javax.persistence.Persistence
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)

I presume you have a classpath setup.

When I run this from inside intellij it runs fine.

I got a similar error (java.lang.ClassNotFoundException: org.postgresql.Driver) after upgrading postgresql driver from 42.2.2 to 42.3.4. After a lot of trial and error, I found out that postgresql in versions starting from 42.2.13 fails to be properly recognized by the classloader if there is a INDEX.LIST file in the JAR archive. Project in which the issue can be reproduced is in my github repo "DBTest".

@davecramer
Copy link
Member

davecramer commented Jun 2, 2022

public class LoadDriver {
    public static void main(String[] args) throws ClassNotFoundException{
        Class.forName("org.postgresql.Driver");
    }
}

executes fine both inside intellij and manually using 42.3.6 and jdk 1.8

@hiroSzymon
Copy link

hiroSzymon commented Jun 2, 2022

public class LoadDriver {
    public static void main(String[] args) throws ClassNotFoundException{
        Class.forName("org.postgresql.Driver");
    }
}

executes fine both inside intellij and manually using 42.3.6 and jdk 1.8

Have you tried launching it after building a JAR archive? I've added simple ones to my repo https://github.com/hiroSzymon/DBTest to make testing and verification easier. The only difference between the JARs is the mentioned INDEX.LIST file.

@davecramer
Copy link
Member

I ran java -cp ./lib/postgresql-42.3.6.jar:target/classes LoadDriver locally

@hiroSzymon
Copy link

I ran java -cp ./lib/postgresql-42.3.6.jar:target/classes LoadDriver locally

This way it works. The issue happens only when running it with the JAR.

@davecramer
Copy link
Member

Did you add the services file to the jar ? https://github.com/pgjdbc/pgjdbc/tree/master/pgjdbc/src/main/resources/META-INF/services

@hiroSzymon
Copy link

hiroSzymon commented Jun 2, 2022

No. The only services file is in the postgresql-42.3.4.jar downloaded from maven repository (to be sure, I've compared SHA-256 between the maven one and downloaded directly from https://jdbc.postgresql.org/download/postgresql-42.3.4.jar and they are equal).

@davecramer
Copy link
Member

so I cloned your repo and built it using mvn package
now what ?

@vlsi
Copy link
Member

vlsi commented Jun 2, 2022

I believe the issue has been fixed in 42.2.19 2df6c97, and 42.3.0 f3301c1

@hiroSzymon , please file a new issue with the test case

@vlsi vlsi closed this as completed Jun 2, 2022
@hiroSzymon
Copy link

hiroSzymon commented Jun 2, 2022

so I cloned your repo and built it using mvn package now what ?

As vlsi suggested, I've created new issue #2527.
To reproduce, you have to uncomment or add <index>true</index> in pom.xml before building.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants