Hibernate Envers fails with @Converter and Attribu

2019-01-24 14:35发布

问题:

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?

回答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;
    ...
    }


回答2:

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.



回答3:

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.



回答4:

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.