8

I am using Hibernate 4.3.4 with Envers, and MySql 5.6.

Without a JPA 2.1 converter, the Party entity below fails at Configuration.buildSessionFactory() as it should, since Hibernate doesn't know what to do with the Name class:

@Entity
@Audited
public class Party
    {
    protected Name name;
    ...
    }

The exception is:

org.hibernate.MappingException: 
  Could not determine type for: 
    ModuloADM.Party.Name, 
    at table: Party, for columns: [org.hibernate.mapping.Column(name)]

To fix this, I then add this converter:

@Converter (autoApply=true)
public class NametoStringConverter
      implements AttributeConverter<Name, String>
    { ... }

And the exception now changes to:

org.hibernate.MappingException: 
  Could not determine type for: 
    BasicType adapter for AttributeConverter<Name,String>, 
    at table: History_Party, for columns: [org.hibernate.mapping.Column(name)]

This is now failing at the Envers auditing table for the Party entity. Note that History_Party is the name of the audit table, as chosen by config.setProperty("org.hibernate.envers.audit_table_prefix", "History_").

The complete stacktrace is:

org.hibernate.MappingException: 
  Could not determine type for: 
    BasicType adapter for AttributeConverter<Name,String>, 
    at table: History_Party, for columns: [org.hibernate.mapping.Column(name)]

  at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:336)
    at org.hibernate.tuple.PropertyFactory.buildEntityBasedAttribute(PropertyFactory.java:246)
    at org.hibernate.tuple.entity.EntityMetamodel.<init>(EntityMetamodel.java:227)
    at org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEntityPersister.java:520)
    at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:148)
    at sun.reflect.GeneratedConstructorAccessor43.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
    at org.hibernate.persister.internal.PersisterFactoryImpl.create(PersisterFactoryImpl.java:163)
    at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:135)
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:401)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1857)

How do I solve this? Is Envers even compatible with AttributeConverters?

Marcelo Glasberg
  • 29,013
  • 23
  • 109
  • 133

5 Answers5

1

Try using @Convert in Party Entity. Sometimes autoApply flag will not work

@Entity
@Audited
public class Party
    {
    @Convert(converter = NametoStringConverter.class)
    protected Name name;
    ...
    }
shazin
  • 21,379
  • 3
  • 54
  • 71
  • Thanks, shazin. I had already tested this and it doesn't work. It wouldn't solve my problem even if it did, because I need the autoApply. Please note the autoApply also works if I remove Envers auditing. – Marcelo Glasberg Mar 13 '14 at 18:33
  • 1
    We had the same problem (but are not using *Envers*) and **it works with Hibernate 4.3.7.Final this way** :) ... it should be related to what *dalcorta* said, that the `@Column` annotation may cause the `@Converter(autoApply = true)` on the `AttributeConverter` to be ignored. – Andreas Covidiot Jul 17 '17 at 09:18
  • using generics may be another cause: https://stackoverflow.com/a/28281463/1915920 – Andreas Covidiot Jul 17 '17 at 09:24
  • To my first comment: but we had an **unused dependency to *Envers 5.1.0.Final* in another subproject/pom** and removing it (actually it was enough to set it from `compile` **scope to `provided`**) fixed it as well. – Andreas Covidiot Jul 17 '17 at 09:40
  • another fix we applied was to not put **mapping infos/annotated classes in a separate project** which are not auto-scanned by hibernate automatically: https://stackoverflow.com/questions/1780341/do-i-need-class-elements-in-persistence-xml – Andreas Covidiot Jul 17 '17 at 12:20
1

This seems to be a known problem with Hibernate Envers (HHH-9042).

A simple workaround would be a manual invocation of the Convter and an additional transient field, like this:

@Entity
public class Party {

  protected Name name;

  @Transient
  protected String nameString;

  //...

  public void setName(Name name) {
    this.nameString = (new NametoStringConverter()).convertToDatabaseColumn(name);
    this.name = name;
  }

  //...

  public void setNameString(String nameString) {
    this.name = (new NametoStringConverter()).convertToEntityAttribute(nameString);
    this.nameString = nameString;
  }

}

Depending on the conversion functions, the code could be further simplified by making them staticand importing them.

Roland Ewald
  • 4,630
  • 3
  • 35
  • 49
  • Well, I am actually the reporter of ticket HHH-9042 you refer to. – Marcelo Glasberg Aug 24 '14 at 21:42
  • Ah, I see. I added a link to this question to the comment section of `HHH-9042` so that we can update this here once the issue is closed. Also, it's good to know that it is an 'official' bug that is considered open by the Hibernate Envers team. – Roland Ewald Aug 25 '14 at 09:55
  • 3
    The bug has been reported as fixed a few days ago, but the fix won't be backported to Hibernate 4.3. So it seems we either have to wait for 5.0, or fall back to user types instead of using AttributeConvertes. – Dario Seidl Mar 25 '15 at 16:31
0

I see the text "GeneratedConstructorAccessor43" in the exception. May be you need a public void constructor so that JPA can create an instance of NametoStringConverter.

The default constructor should work but check if you have another one with receives parameters or not public.

borjab
  • 11,149
  • 6
  • 71
  • 98
0

I had the same problem, what I found out that it only occured when I didn't put the @Column annotation with columnDefinition = "VARCHAR(255)" to the Enum. So I think that is a better work around than what in hibernate tracker has.

dalcorta
  • 85
  • 4
0

In case you need to specify a column name for the column (in this example "C_NAME") you need to add @Column annotation.

@Entity
@Audited
public class Party
    {
    @Convert(converter = NametoStringConverter.class)
    @Column( name = "C_NAME" )
    protected Name name;
    ...
    }

Note below code will not work and will result in "Could not determine type for: " error because Converter annotation will be ignored.

@Entity
@Audited
public class Party
    {
    @Convert(converter = NametoStringConverter.class)
    @Column( name = "C_NAME", nullable=true )   // DOESN'T WORK
    protected Name name;
    ...
    }
Joaquim Perez
  • 97
  • 1
  • 3