0

I have a hibernate + oracle program. In that, I have a many-to-many relationship between "Applications" and "IdentityProviders" table via the "ApplicationIdentityProviders" table. I am getting the following error while running the program:

Exception in thread "main" java.lang.RuntimeException: org.hibernate.MappingException: 
Could not determine type for: String, at table: identity_providers, for columns: [org.hibernate.mapping.Column(issuer)]
at com.oracle.hibernate.OCIAuthManager.setupTenant1Pdb1(OCIAuthManager.java:246)
at com.oracle.hibernate.OCIAuthManager.main(OCIAuthManager.java:283)

I am unable to figure out why. Applications.java is here. IdentityProviders.java is here. ApplicationIdentityProviders.java is here. Main class is here. Applications.hbm.xml is as follows:

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 

<hibernate-mapping>
 <class name = "Applications" table = "applications">

  <meta attribute = "class-description">
     This class contains the applications details. 
  </meta>

  <id name = "application_id" type = "int" column = "application_id">
     <generator class="native"/>
  </id>

  <set name = "application_id_providers" cascade="save-update" table="application_identity_providers">
     <key column = "application_id"/>
     <many-to-many column = "identity_provider_id" class="IdentityProviders"/>
  </set>

  <property name = "application_name" column = "application_name" type = "string"/>
  <property name = "attr" column = "attr" type = "short"/>
  <property name = "salary" column = "salary" type = "int"/>

 </class>

 <class name = "IdentityProviders" table = "identity_providers">

  <meta attribute = "class-description">
     This class contains the identity providers' details. 
  </meta>

  <id name = "identity_provider_id" type = "int" column = "identity_provider_id">
     <generator class="native"/>
  </id>

  <property name = "attr" column = "attr" type = "short"/>
  <property name = "protocols" column = "protocols" type = "short"/>
  <property name = "issuer" column = "issuer" type = "String"/>
  <property name = "cert1" column = "cert1" type = "String"/>
  <property name = "cert2" column = "cert2" type = "String"/>
  <property name = "is_tenant_default" column = "is_tenant_default" type = "short"/>

 </class>

</hibernate-mapping>

hibernate-1.cfg.xml is as follows:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>

    <property name="connection.url">jdbc:oracle:thin:@//localhost:1521/t1p1.oradev.oraclecorp.com</property>
    <property name="connection.username">username</property>
    <property name="connection.password">password</property>
    <property name="connection.driver_class">oracle.jdbc.OracleDriver</property>
    <property name="dialect">org.hibernate.dialect.Oracle12cDialect</property>

    <property name="show_sql">true</property>

    <property name="format_sql">true</property>
    <property name="hbm2ddl.auto">create</property>

    <!-- JDBC connection pool (use the built-in) -->
    <property name="connection.pool_size">1</property>
    <property name="current_session_context_class">thread</property>

    <mapping resource = "Applications.hbm.xml"/>

  </session-factory>
</hibernate-configuration>

Where am I going wrong? Kindly help.

Update 1: @Guillaume's answer worked. But I am now getting the following error:

Exception in thread "main" java.lang.RuntimeException:
org.hibernate.MappingException: An association from the table 
application_identity_providers refers to an unmapped class: 
IdentityProviders at
com.oracle.hibernate.OCIAuthManager.setupTenant1Pdb1(OCIAuthManager.java:246) 
at com.oracle.hibernate.OCIAuthManager.main(OCIAuthManager.java:283)

Update 2: I resolved the error in update 1. Now I am getting the following error: ERROR: ORA-01400: cannot insert NULL into ("SYS"."APPLICATION_IDENTITY_PROVIDERS"."APPLICATION_IDENTITY_PROVIDER_ID")

This error occurs in the intermediate table holding the primary keys of two other tables which have a many-to-many mapping. In ApplicationIdentityProviders.java, I have:

@Id
@SequenceGenerator(name="seq",sequenceName="oracle_seq",allocationSize=1)        
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
private int application_identity_provider_id;

When I run the program, the relevant output snippet is: Hibernate:

create table application_identity_providers (
application_identity_provider_id number(10,0) not null,
application_id number(10,0) not null,
identity_provider_id number(10,0) not null,
is_application_default number(5,0) not null,
primary key (application_id, identity_provider_id)
)

Where am I going wrong?

Update 3: Given "application_name" in "applications" table, fetch entire content in "identity_providers" and "saml_identity_providers" tables. How to do it?

I tried the following:

Query query = entitymanager.createQuery("select a from Applications a join 
fetch a.ApplicationIdentityProviders ap " +
"join fetch ap.IdentityProviders ip where a.application_name = 
'newApplicationName'");

It is giving me this error:

org.springframework.beans.factory.BeanCreationException: Error creating bean 
with name 'applicationsRepository' defined in file 
[D:\filepath\ApplicationsRepository.class]: Bean instantiation via 
constructor failed; nested exception is 
org.springframework.beans.BeanInstantiationException: Failed to instantiate 
[ApplicationsRepository]: Constructor threw exception; nested exception is 
java.lang.IllegalArgumentException: org.hibernate.QueryException: could not 
resolve property: ApplicationIdentityProviders of: Applications [select a 
from com.package.entities.Applications a join fetch 
a.ApplicationIdentityProviders ap join fetch 
ap.IdentityProviders ip where a.application_name = 'newApplicationName']
pikaraider
  • 187
  • 1
  • 14

3 Answers3

0

I think that your type should be lower case string (not String) for these lines here:

<property name = "issuer" column = "issuer" type = "string"/>
<property name = "cert1" column = "cert1" type = "string"/>
<property name = "cert2" column = "cert2" type = "string"/>

I think that you also need to declare the qualified names of your Java classes in your mapping files, this can be done by adding the packagename in the hibernate mapping element:

<hibernate-mapping package="com.oracle.hibernate">
Guillaume
  • 14,306
  • 3
  • 43
  • 40
  • that worked. But I am now getting the following error: Exception in thread "main" java.lang.RuntimeException: org.hibernate.MappingException: An association from the table application_identity_providers refers to an unmapped class: IdentityProviders at com.oracle.hibernate.OCIAuthManager.setupTenant1Pdb1(OCIAuthManager.java:246) at com.oracle.hibernate.OCIAuthManager.main(OCIAuthManager.java:283) – pikaraider Sep 28 '18 at 10:31
  • You must give Hibernate the qualified class names (package + name) and/or declare the package in the hibernate-mapping element (see my edit) – Guillaume Sep 28 '18 at 17:30
  • I have already given the qualified class names in hibernate.cfg.xml file. Still I am getting the same error as in Update 1. – pikaraider Sep 30 '18 at 17:17
  • is for annotations based mapping, you're not using annotations. The qualified name should be added in the mapping file, have you tried the change I suggested? – Guillaume Oct 01 '18 at 12:29
  • I tried your change and it is working now. I have a query: given "application_name" in "applications" table, fetch entire content in "identity_providers" and "saml_identity_providers" tables. How do I accomplish this? – pikaraider Oct 04 '18 at 09:17
0

The faster way is using Hibernate tools to generate your mapping file automatically. Please refer to following articles.

How to install Hibernate Tools in Eclipse?
http://www.mkyong.com/hibernate/how-to-generate-code-with-hibernate-tools/

Miller Cy Chan
  • 897
  • 9
  • 19
  • I am getting an error as posted in Update 1. How do I resolve it? – pikaraider Sep 28 '18 at 11:14
  • I did that. I am getting the same error still. Where am I going wrong? I cannot see where an association is referring to an unmapped class. Kindly guide. – pikaraider Sep 30 '18 at 17:18
  • Just try to set the following property (inverse) from this line to false: This will ensure that the insertion will work properly in all 3 tables. – Miller Cy Chan Oct 02 '18 at 06:31
  • It is working now. Given "application_name" in "applications" table, fetch entire content in "identity_providers" and "saml_identity_providers" tables. How do I accomplish this? – pikaraider Oct 04 '18 at 09:16
  • Please refer to https://stackoverflow.com/questions/8815209/hibernate-mapping-setting-lazy-false – Miller Cy Chan Oct 04 '18 at 09:22
  • I couldn't understand the content in above link. I already have lazy="true". Can you please guide how to create the above query using JPA EntityManager? – pikaraider Oct 04 '18 at 09:53
  • select a from Applications a join fetch a.applicationIdentityProviders ap join fetch ap.identityProviders ip where a.applicationName = ? – Miller Cy Chan Oct 05 '18 at 06:30
  • select a from Applications a join fetch a.application_id_providers ap where a.applicationName = :applicationName – Miller Cy Chan Oct 08 '18 at 02:59
  • How to display the data? I'm doing: Query query = entitymanager.createQuery("select a from Applications a join fetch a.application_id_providers ap where a.application_name = 'newApplicationName'"); List resultList = query.getResultList(); for (Applications a : resultList) { System.out.println(a.getApplication_name()); It is showing unexpected token for "for" loop and unknown class for "resultList". Where is the error? – pikaraider Oct 08 '18 at 06:18
  • I am executing the following query (isn't this the "right" query for what i want?): Query query = entitymanager.createQuery("select a from Applications a join fetch a.ApplicationIdentityProviders ap join fetch ap.IdentityProviders ip where a.application_name = 'newApplicationName'"); My Applications.hbm.xml is as follows: https://pastebin.com/Hkuu1cCt And getting the following error trace: https://pastebin.com/7Q5jtt7u How do I resolve it? – pikaraider Oct 08 '18 at 10:44
  • List resultList = (Applications) query.getResultList(); – Miller Cy Chan Oct 09 '18 at 02:11
  • What is the content of com.oracle.OSvC.oci.security.authorization.persistence.repository.ApplicationsRepository.java ? As long as a simple query failed, not effective to test any other complex query. – Miller Cy Chan Oct 09 '18 at 02:18
  • ApplicationsRepository.java content - https://pastebin.com/y2LMhBhL The line of code you sent is giving syntax error. It has to be List resultList = (List) query.getResultList(); i believe. – pikaraider Oct 09 '18 at 04:34
  • I have resolved the error in Update 3. However, I feel the query is incorrect. What i want is this: 1) given application name in applications table, fetch entire content in identity_providers and saml_identity_providers tables, 2) given issuer in identity_providers table, fetch saml_identity_providers table. How do I do this? – pikaraider Oct 09 '18 at 07:40
  • Query 2 is returning null. I am doing: Query query2 = entitymanager.createQuery("SELECT sip.saml_identity_provider_id, sip.attr, sip.identity_provider_id, sip.sso_service_url, sip.logout_service_url, sip.sign_method, sip.sign_digest_method, sip.sign_attr, sip.custom_audience FROM SamlIdentityProviders sip JOIN IdentityProviders ip ON sip.identity_provider_id = ip.identity_provider_id AND ip.issuer = 'issuerName'"); List samlIdentityProvidersList = (List)query2.getResultList(); samlIdentityProvidersList is null here. What is wrong? – pikaraider Oct 09 '18 at 11:07
0

In Application.java
Remove the following line:

private Set<IdentityProviders> application_id_providers;

Add the following lines:

@ManyToMany(cascade = { 
    CascadeType.PERSIST, 
    CascadeType.MERGE
})
@JoinTable(name = "application_identity_providers",
    joinColumns = @JoinColumn(name = "application_id"),
    inverseJoinColumns = @JoinColumn(name = "identity_provider_id")
)
private Set<IdentityProviders> id_providers;

In IdentityProviders.java
Add the following lines:

@ManyToMany(mappedBy = "id_providers")
private Set<Applications> applications;

@OneToMany(
    cascade = CascadeType.ALL, 
    orphanRemoval = true
)
private Set<SamlIdentityProviders> si_providers;

Then the query could be:

SELECT a from Applications a JOIN fetch a.id_providers ip JOIN fetch ip.si_providers sip 
WHERE a.application_name = 'newApplicationName' AND ip.issuer = 'issuerName'
Miller Cy Chan
  • 897
  • 9
  • 19
  • There are 2 different queries I need: 1) given application name in applications table, fetch entire content in identity_providers and saml_identity_providers tables, 2) given issuer in identity_providers table, fetch saml_identity_providers table. I am able to execute sql commands to achieve 1) and 2) but not able to do it using JPA queries. – pikaraider Oct 10 '18 at 04:35
  • Also, how would the hbm.xml change to reflect the @OneToMany mapping? hbm.xml file: https://pastebin.com/1eyKErQk – pikaraider Oct 10 '18 at 04:40
  • As you can execute native query, please refer to https://stackoverflow.com/questions/13012584/jpa-how-to-convert-a-native-query-result-set-to-pojo-class-collection and look for "With the arrival of JPA 2.1, we can use the @SqlResultSetMapping annotation to solve the problem" – Miller Cy Chan Oct 11 '18 at 02:13