JPA 2.1 Attribute Converter convert enum still insert int - java

i'm using spring data jpa with hibernate as provider.
i'm trying to persist my enums on varchar(enum.tostring) instead of (0,1,2)
my enum class:
public enum MagasinType {
PRINCIPAL {
#Override
public String toString() {
return "Principale".toUpperCase();
}
},
SECONDARY {
#Override
public String toString() {
return "Secondaire".toUpperCase();
}
},
MOBILE {
#Override
public String toString() {
return "Mobile".toUpperCase();
}
};
public abstract String toString();
}
my converter
#Converter(autoApply = true)
public class MagasinConverter implements attributeConverter <MagasinType,String>{
#Override
public String convertToDatabaseColumn(MagasinType magasinType) {
switch (magasinType){
case MOBILE:return "MOBILE";
case PRINCIPAL:return "PRINCIPAL";
case SECONDARY:return "SECONDARY";
default:throw new IllegalArgumentException("valeur incorrecte" + magasinType);
}
}
#Override
public MagasinType convertToEntityAttribute(String s) {
switch (s){
case "MOBILE": return MagasinType.MOBILE;
case "SECONDARY": return MagasinType.SECONDARY;
case "PRINCIPAL": return MagasinType.PRINCIPAL;
default:throw new IllegalArgumentException("valeur incorrecte" + s);
}}}
my entity
#Entity
#Table(name = "MAGASIN")
public class Magasin extends AbstractEntity {
#Column(name = "LIBELLE", nullable = false)
private String libelle;
#Column(name = "DESCR")
private String descr;
#Convert(converter = MagasinConverter.class)
private MagasinType type;
#Column(name = "LOCATION")
private String localisation;
#Version
private long version;
//getters setters omitted
}
my java config : https://gist.github.com/anonymous/480ef7a58cdcc50e7481
my app.properties : https://gist.github.com/anonymous/685eaca98fcba9c33872
and finally my test method : https://gist.github.com/anonymous/8bb60fee39a201558e19
please help me on it, i want to use #convert new jpa2.1 feature instead of
#enumerated

i tried to put the annotation on the getter and it works.
now i can call the #convert to convert enums to strings and visversa when pulling from database.
the same problem happened when i added #manytoOne on my class attribute, i got a weired problem, no column was added to the table entity.
but when i annotated the getter. every thing was ok.
please take a look at my github repo to further infos
https://github.com/zirconias/RFID_REWRITE

Related

Extending/modifying generated entities in Hibernate

I am creating a REST api service for a mysql database. I've generated classes using IntelliJ's persistence tool. It does a pretty good job.
There are some quirks to the schema that I am working with. The users want the endpoints to be accessible by another property other than the "id" primary key column.
Ex: /object/<name property>' versus/object/`.
Here is the catch though. The schema can change. The name property is not going anywhere though so I can safely assume that will always be on the object.
I've learned that you can use Superclasses to force these generated entites to have custom properties without affecting the database schema. I dont want to make a model change in the generated entity and have that update the database table layout as it is not my database.
I have a class called Animal.
#Entity
#Table(name = "animals", schema = "xyz123", catalog = "")
public class AnimalEntity extends AnimalSuperclass {
private Integer id;
private String name;
private String description;
#Id
#Column(name = "id", nullable = false)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Basic
#Column(name = "name", nullable = true, length = 80)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Basic
#Column(name = "description", nullable = true, length = 255)
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RoleEntity that = (RoleEntity) o;
return Objects.equals(id, that.id) &&
Objects.equals(name, that.name) &&
Objects.equals(description, that.description);
}
#Override
public int hashCode() {
return Objects.hash(id, name, description);
}
}
I have to manually add extends AnimalSuperclass. Which is fine for now. Eventually I am going to try to generate these using .xmls on runtime.
Then I have this superclass..
#MappedSuperclass
public class AnimalSuperclass implements Serializable {
private String testMessage;
private String name;
private Integer id;
#Transient
public String getTestMessage() {
return this.testMessage;
}
public void setTestMessage(String id) {
this.testMessage = testMessage;
}
}
What I want to do is force the #Id annotation to be on the name property from within the superclass. Something like this..
#MappedSuperclass
public class AnimalSuperclass implements Serializable {
private String testMessage;
private String name;
private Integer id;
#Transient
public String getTestMessage() {
return this.testMessage;
}
public void setTestMessage(String id) {
this.testMessage = testMessage;
}
#Basic
#Id
#Column(name = "name", nullable = false, length = 15)
private String getName() {
return name;
}
private void setName(String name) {
this.name = name;
}
#NaturalId
#Column(name = "id", nullable = false)
private Integer getId() {
return id;
}
private void setId(Integer id) {
this.id = id;
}
}
How do I go about doing that? Currently this throws an error when I hit the endpoint: {"cause":null,"message":"Id must be assignable to Serializable!: null"}
Java is not my first language so I am not an expert by any means. But from what I've read, its not possible to override subclass properties from the superclass. Is there a better way to approach this, maybe by using RepositoryRestConfiguration? I am using PagingAndSortingRepository to serve these entities. I cannot extend the entities and use my superclass as a child as that creates a dType property in the schema and I cannot alter the table layout.
There is no hard link between the request and your entity. In your repository you can write methods that can query the data that is brought it from the request.
For example if they are requesting a name you can do something like
Page<AnimalEntity> findByName(String name, Pageable pageable);
in your Repository. Spring will take care of the rest and then you can call this in your controller.
#Service
public class AnimalService {
#Autowired
private AnimalEntityRepository animalRepo;
public Page<AnimalEntity> findAnimal(String name) {
Page<AnimalEntity> animals = animalRepo.findByName(name, new PageRequest(1,20));
return animals;
}
}
One thing to mention is that depending on how you configured Hibernate when sending an entity back to the client and the entity is seralized you might get an failed to lazy initialize error. If that is the case your entities will have to be converted to a POJO (plain old java object) and that sent back.

Null columns are created on either tables when accessing data using Spring Data JPA

I am new to Spring Data JPA and Hibernate. By looking at different examples I built a working model for CRUD operations on one entity, I am having trouble in joining two tables to extract AF_NAME using AF_ID from another table which is Foreign key. A null column is created with the names of and while accessing, null is returned.please check if I am following preocedure for joins and point me to any tutorial know.
I followed this solution and still there is no progress.
#Entity
#Configuration
#EnableAutoConfiguration
#Table(name = "AFF_CONFIG")
public class AFF_CONFIG implements Serializable {
#Id
#Column(name = "AFF_CONFIG_ID")
private String AFF_CONFIG_ID;
#Column(name = "AFF_ID")
private String AFF_ID;
#Column(name = "CH_ID")
private String CH_ID;
#Column(name = "M_ID")
private Long M_ID;
#Column(name = "KEY")
private String KEY;
#Column(name = "VALUE")
private String VALUE;
#Column(name = "SYSTEM")
private String SYSTEM;
private AFF aff;
#LazyCollection(LazyCollectionOption.TRUE)
#ManyToOne
#JoinColumn(name = "AFF_ID")
public AFF getAff() {
return aff;
}
public void setAffiliate(AFF aff) {
this.aff = aff;
}
public String getAFF_CONFIG_ID() {
return AFF_CONFIG_ID;
}
public void setAFF_CONFIG_ID(String aFF_CONFIG_ID) {
AFF_CONFIG_ID = aFF_CONFIG_ID;
}
public String getAFF_ID() {
return AFF_ID;
}
public void setAFF_ID(String aFF_ID) {
AFF_ID = AFF_ID;
}
public String getCH_ID() {
return CH_ID;
}
public void setCHANNEL_ID(String cH_ID) {
CH_ID = cH_ID;
}
public Long getM_ID() {
return M_ID;
}
public void setM_ID(Long m_ID) {
M_ID = m_ID;
}
public String getKEY() {
return KEY;
}
public void setKEY(String kEY) {
KEY = kEY;
}
public String getVALUE() {
return VALUE;
}
public void setVALUE(String vALUE) {
VALUE = vALUE;
}
public String getSYSTEM() {
return SYSTEM;
}
public void setSYSTEM(String sYSTEM) {
SYSTEM = sYSTEM;
}
Second entity is:
#Entity
#Table(name = "AFF")
public class AFF implements Serializable {
#Column(name = "AFF_NAME")
private String AFF_NAME;
#Column(name = "AFF_CODE")
private String AFF_CODE;
#Id
#Column(name = "AFF_ID")
private String AFF_ID;
private Set<AFF_CONFIG> someAff = new HashSet<AFF_CONFIG>();
#LazyCollection(LazyCollectionOption.TRUE)
#OneToMany(cascade = CascadeType.ALL, mappedBy = "aff")
public Set<AFF_CONFIG> getSomeAff() {
return someAff;
}
public void setSomeAff(Set<AFF_CONFIG> someAff) {
this.someAff = someAff;
}
public String getAFF_ID() {
return AFF_ID;
}
public void setAFF_ID(String aFF_ID) {
AFF_ID = aFF_ID;
}
public String getAFF_NAME() {
return AFF_NAME;
}
public void setAFF_NAME(String aFF_NAME) {
AFF_NAME = aFF_NAME;
}
public String getAFF_CODE() {
return AFF_CODE;
}
public void setAFF_CODE(String aFF_CODE) {
AFF_CODE = aFF_CODE;
}
Since this is many to one relation I created set type in one and object type in another as defined in other places.Created a repository by extending crud and added a query. Excise the bunch of different annotations, I included them in hoping to solve the null entry.
#Repository
public interface MarketRepository extends CrudRepository<AFF_CONFIG,String> {
Page<AFF_CONFIG> findAll(Pageable pageable);
#Query("Select a,b from AFF_CONFIG a, AFF b where a.AFF_ID = b.AFF_ID" )
public List<AFF_CONFIG> getAffData();
}
the applicatoin is working fine even after some tinkering until I Included these annotations. Now there is this error:
Caused by: org.hibernate.MappingException: Could not determine type for: java.util.Set, at table: aff.
I solved the issue with the help of my Supervisor. Looks like we have to follow naming specifications for Class and variables. And one more correction is to remove collection type object and change it to just object (removed set in aff class).I will post the corrected later, to compare and contrast.

Setting up query for specific field of Hibernate entity

I use spring and hibernate. The following situation occured and I don't know if it's really possible to implement. Will appreciate any help.
For example, there is a hibernate entity
#Entity
public class TestEntity {
private String field1;
private String field2;
private String specField;
#Column(name = "field1")
public String getField1() {
return field1;
}
#Column(name = "field2")
public String getField2() {
return field2;
}
public String getSpecField() {
return (field1 != null ? field1 : field2);
}
}
And I need the value for specField to be generated by SQL query and not by java code.
Something like this
#Entity
public class TestEntity {
private String field1;
private String field2;
private String specField;
#Column(name = "field1")
public String getField1() {
return field1;
}
#Column(name = "field2")
public String getField2() {
return field2;
}
#Query(value= "COALESCE(field1, field2)")
public String getSpecField() {
return specField;
}
}
I was told that there should be ability to do so. But didn't find anything that approves this.
it's not actually important what exactly query does. I need that specField will be taken by some query and not by java code. Is it possible?
Thanks for help.
UPDATE Thanks to #premkumar, for advicing to use #Formula
So now I have
#Entity
public class TestEntity {
private String field1;
private String field2;
private String specField;
#Column(name = "field1")
public String getField1() {
return field1;
}
#Column(name = "field2")
public String getField2() {
return field2;
}
#Formula("COALESCE(field2, field2)")
public String getSpecField() {
return (field1 != null ? field1 : field2);
}
}
But app fails to start on bean initialization with
NullPointerException at org.springframework.orm.hibernate3.LocalSessionFactoryBean.newSessionFactory
I tried also the following:
Put formula above "private String specField" - app started, but hibernate failed on could not find spec_field in database
Put #Formula and #Transient on getter - app started, no errors, but specField is always null. It looks like hibernate totally ignored it
If you are using hibernate, try the following:
#Formula("COALESCE(field1, field2)")
public String getSpecField() {
return specField;
}
Note:- As far as I know there is no alternative in JPA. Beware this will mixup hibernate and jpa annotations.
Why not:
public String getSpecField() {
return MoreObjects.firstNonNull(field1,field2);
}
You can leverage the JPA Callback methods:
Create a EntityListener:
public class MyEntityListener {
#PrePersist
#PreUpdate
public void prePersist(Object object) {
if(object instanceOf TestEntity ) {
object.specField = object.field1 != null ? object.field1 : object.field2
}
}
}
Annotate your class with #EntityListener:
#Entity
#EntityListeners(MyEntityListener .class)
public class TestEntity {
private String field1;
private String field2;
private String specField;
//default cons - getters and setters
}

Specify field is transient for MongoDB but not for RestController

I'm using spring-boot to provide a REST interface persisted with MongoDB. I'm using the 'standard' dependencies to power it, including spring-boot-starter-data-mongodb and spring-boot-starter-web.
However, in some of my classes I have fields that I annotate #Transient so that MongoDB does not persist that information. However, this information I DO want sent out in my rest services. Unfortunately, both MongoDB and the rest controller seem to share that annotation. So when my front-end receives the JSON object, those fields are not instantiated (but still declared). Removing the annotation allows the fields to come through in the JSON object.
How I do configure what is transient for MongoDB and REST separately?
Here is my class
package com.clashalytics.domain.building;
import com.clashalytics.domain.building.constants.BuildingConstants;
import com.clashalytics.domain.building.constants.BuildingType;
import com.google.common.base.Objects;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import java.util.*;
public class Building {
#Id
private int id;
private BuildingType buildingType;
private int level;
private Location location;
// TODO http://stackoverflow.com/questions/30970717/specify-field-is-transient-for-mongodb-but-not-for-restcontroller
#Transient
private int hp;
#Transient
private BuildingDefense defenses;
private static Map<Building,Building> buildings = new HashMap<>();
public Building(){}
public Building(BuildingType buildingType, int level){
this.buildingType = buildingType;
this.level = level;
if(BuildingConstants.hpMap.containsKey(buildingType))
this.hp = BuildingConstants.hpMap.get(buildingType).get(level - 1);
this.defenses = BuildingDefense.get(buildingType, level);
}
public static Building get(BuildingType townHall, int level) {
Building newCandidate = new Building(townHall,level);
if (buildings.containsKey(newCandidate)){
return buildings.get(newCandidate);
}
buildings.put(newCandidate,newCandidate);
return newCandidate;
}
public int getId() {
return id;
}
public String getName(){
return buildingType.getName();
}
public BuildingType getBuildingType() {
return buildingType;
}
public int getHp() {
return hp;
}
public int getLevel() {
return level;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public BuildingDefense getDefenses() {
return defenses;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Building building = (Building) o;
return Objects.equal(id, building.id) &&
Objects.equal(hp, building.hp) &&
Objects.equal(level, building.level) &&
Objects.equal(buildingType, building.buildingType) &&
Objects.equal(defenses, building.defenses) &&
Objects.equal(location, building.location);
}
#Override
public int hashCode() {
return Objects.hashCode(id, buildingType, hp, level, defenses, location);
}
}
As is, hp and defenses show up as 0 and null respectively. If I remove the #Transient tag it comes through.
As long as you use org.springframework.data.annotation.Transient it should work as expected. Jackson knows nothing about spring-data and it ignores it's annotations.
Sample code, that works:
interface PersonRepository extends CrudRepository<Person, String> {}
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.mapping.Document;
#Document
class Person {
#Id
private String id;
private String name;
#Transient
private Integer age;
// setters & getters & toString()
}
#RestController
#RequestMapping("/person")
class PersonController {
private static final Logger LOG = LoggerFactory.getLogger(PersonController.class);
private final PersonRepository personRepository;
#Autowired
PersonController(PersonRepository personRepository) {
this.personRepository = personRepository;
}
#RequestMapping(method = RequestMethod.POST)
public void post(#RequestBody Person person) {
// logging to show that json deserialization works
LOG.info("Saving person: {}", person);
personRepository.save(person);
}
#RequestMapping(method = RequestMethod.GET)
public Iterable<Person> list() {
Iterable<Person> list = personRepository.findAll();
// setting age to show that json serialization works
list.forEach(foobar -> foobar.setAge(18));
return list;
}
}
Executing POST http://localhost:8080/person:
{
"name":"John Doe",
"age": 40
}
Log output Saving person: Person{age=40, id='null', name='John Doe'}
Entry in person collection:
{ "_id" : ObjectId("55886dae5ca42c52f22a9af3"), "_class" : "demo.Person", "name" : "John Doe" } - age is not persisted
Executing GET http://localhost:8080/person:
Result: [{"id":"55886dae5ca42c52f22a9af3","name":"John Doe","age":18}]
I solved by using #JsonSerialize. Optionally you can also opt for #JsonDeserialize if you want this to be deserailized as well.
#Entity
public class Article {
#Column(name = "title")
private String title;
#Transient
#JsonSerialize
#JsonDeserialize
private Boolean testing;
}
// No annotations needed here
public Boolean getTesting() {
return testing;
}
public void setTesting(Boolean testing) {
this.testing = testing;
}
The problem for you seems to be that both mongo and jackson are behaving as expected. Mongo does not persist the data and jackson ignores the property since it is marked as transient. I managed to get this working by 'tricking' jackson to ignore the transient field and then annotating the getter method with #JsonProperty. Here is my sample bean.
#Entity
public class User {
#Id
private Integer id;
#Column
private String username;
#JsonIgnore
#Transient
private String password;
#JsonProperty("password")
public String getPassword() {
return // your logic here;
}
}
This is more of a work around than a proper solution so I am not sure if this will introduce any side effects for you.
carlos-bribiescas,
what version are you using for it. It could be version issue. Because this transient annotation is meant only for not persisting to the mongo db. Please try to change the version.Probably similar to Maciej one (1.2.4 release)
There was issue with json parsing for spring data project in one of the version.
http://www.widecodes.com/CyVjgkqPXX/fields-with-jsonproperty-are-ignored-on-deserialization-in-spring-boot-spring-data-rest.html
Since you are not exposing your MongoRepositories as restful endpoint with Spring Data REST it makes more sense to have your Resources/endpoint responses decoupled from your domain model, that way your domain model could evolve without impacting your rest clients/consumers. For the Resource you could consider leveraging what Spring HATEOAS has to offer.
I solved this question by implementing custom JacksonAnnotationIntrospector:
#Bean
#Primary
ObjectMapper objectMapper() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
AnnotationIntrospector annotationIntrospector = new JacksonAnnotationIntrospector() {
#Override
protected boolean _isIgnorable(Annotated a) {
boolean ignorable = super._isIgnorable(a);
if (ignorable) {
Transient aTransient = a.getAnnotation(Transient.class);
JsonIgnore jsonIgnore = a.getAnnotation(JsonIgnore.class);
return aTransient == null || jsonIgnore != null && jsonIgnore.value();
}
return false;
}
};
builder.annotationIntrospector(annotationIntrospector);
return builder.build();
}
This code makes invisible org.springframework.data.annotation.Transient annotation for Jackson but it works for mongodb.
You can use the annotation org.bson.codecs.pojo.annotations.BsonIgnore instead of #transient at the fields, that MongoDB shall not persist.
#BsonIgnore
private BuildingDefense defenses;
It also works on getters.

NullPointerException thrown on flush after upgrading to Hibernate 4.1.3 Final

I have just completed an upgrade from Hibernate 3.6 to 4.1.3 Final and at first everything seemed to go fine. However, one of my colleagues recently tested this an in one scenario he gets a NullPointer being thrown from within Hibernate (and this exception was not being thrown before we upgraded for the exact same DB). It is an incredibly strange scenario. We have an entity called BlogPost that looks like the below and it extends some mapped superclasses (that I have also included):
#Entity
#Table(name = "blog_post")
public class BlogPost extends CommunityModelObject implements HasFeedPost {
#Lob
private String title;
#Lob
private String content;
#Enumerated
#Column(nullable = false)
private CBlogPost.Status status = CBlogPost.Status.UNPUBLISHED;
// Reference to the feed post that indicates that this blog post has been published
#OneToOne
#JoinColumn(name = "feed_post_id")
private FeedPost feedPost;
#ManyToOne
#JoinColumn(name = "posted_by_employee_id")
private Employee postedBy;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public CBlogPost.Status getStatus() {
return status;
}
public void setStatus(CBlogPost.Status status) {
this.status = status;
}
#Override
public FeedPost getFeedPost() {
return feedPost;
}
#Override
public void setFeedPost(FeedPost feedPost) {
this.feedPost = feedPost;
}
public Employee getPostedBy() {
return postedBy;
}
public void setPostedBy(Employee postedBy) {
this.postedBy = postedBy;
}
}
#Filter(name = "tenantFilter", condition = "(tenant_id = :tenantId or tenant_id is null)")
#MappedSuperclass
public abstract class CommunityModelObject extends ModelObject {
#IndexedEmbedded(prefix = "tenant", indexNullAs = IndexedEmbedded.DEFAULT_NULL_TOKEN)
#ManyToOne
#JoinColumn(name = "tenant_id")
protected Tenant tenant;
public Tenant getTenant() {
return tenant;
}
public void setTenant(Tenant tenant) {
this.tenant = tenant;
}
/**
* If the Tenant is null then it can be accessed / viewed by the entire "community" / user base
*/
public boolean isCommunityObject() {
return tenant == null;
}
}
#MappedSuperclass
public abstract class ModelObject extends BaseModelObject {
#Id
#GeneratedValue
private Long id;
#Override
public long getId() {
return (id == null ? 0 : id);
}
public void setId(long id) {
this.id = (id == 0 ? null : id);
}
}
#MappedSuperclass
public abstract class BaseModelObject implements java.io.Serializable {
// This annotation ensures that a column is not associated with this member (simply omitting the #Column annotation is not enough since
// that annotation is completely optional)
#Transient
private boolean doNotAutoUpdateDateUpdated = false;
#Version
protected int version;
#Column(name = "date_created")
protected Date dateCreated;
#Column(name = "date_updated")
protected Date dateUpdated;
public abstract long getId();
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public Date getDateCreated() {
return dateCreated;
}
public Date getDateUpdated() {
return dateUpdated;
}
/**
* This will set the dateUpdated to whatever is passed through and it will cause the auto update (pre-update) to NOT occur
*
* #param dateUpdated
*/
public void setDateUpdated(Date dateUpdated) {
doNotAutoUpdateDateUpdated = true;
this.dateUpdated = dateUpdated;
}
public void touch() {
// By setting date updated to null this triggers an update which results in onUpdate being called and the nett
// result is dateUpdated = new Date()
dateUpdated = null;
}
#PrePersist
protected void onCreate() {
dateCreated = new Date();
}
#PreUpdate
protected void onUpdate() {
if (!doNotAutoUpdateDateUpdated) {
dateUpdated = new Date();
}
}
#Override
public boolean equals(Object obj) {
long id = getId();
if (id == 0) {
return this == obj;
}
//Use Hibernate.getClass() because objects might be proxies
return obj != null &&
obj instanceof BaseModelObject &&
Hibernate.getClass(this) == Hibernate.getClass(obj) &&
getId() == ((BaseModelObject)obj).getId();
}
#Override
public int hashCode() {
Long id = getId();
return id == 0 ? super.hashCode() : id.intValue();
}
#Override
public String toString() {
return getClass().getSimpleName() + "-" + getId();
}
}
The strangest thing is happening when I query BlogPost in some scenarios. If I run the query below, for example, in isolation then it works fine but if I run it in amongst a bunch of other queries then I get the exception below:
select b from BlogPost b
java.lang.NullPointerException
at org.hibernate.event.internal.DefaultFlushEntityEventListener.isUpdateNecessary(DefaultFlushEntityEventListener.java:240)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:163)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:225)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:55)
at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1153)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1208)
at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:256)
Now the kicker is that if I take all of the fields from all of the mapped superclasses that I listed above and put them directly into BlogPost and make BlogPost just extend nothing and implement java.io.Serializable then everything works perfectly. This leads me to believe that the bug is either related to mapped superclasses or the Hibernate filter that I am applying to CommunityModelObject.
Any ideas as to how to solve this? I am assuming that it is a newly introduced bug in Hibernate but I may be wrong. This is causing major issues for us since we need to upgrade asap in order to upgrade Hibernate Search which we need to do for a critical bug fix.
Also note that the DB we are using is MySQL with the following custom dialect that I wrote when doing this upgrade to handle our BIT columns:
public class MySQL5InnoDBDialectExt extends MySQL5InnoDBDialect {
private static final String BIT_STRING = "bit";
public MySQL5InnoDBDialectExt() {
super();
registerColumnType(Types.BOOLEAN, BIT_STRING);
}
}
Thanks,
Brent
I sorted this issue out, found the problem by fluke. Here is the resolution as I posted it on the Hibernate forum:
I found the issue. It does not seem to be related to interceptors,
rather to either caching or instrumentation. Basically our app
automatically includes all entities within a very specific package in
our caching scheme and the same classes in our instrumentation. We
generally have all of our entities in this package, however this one
which was causing the issue was the only one not included in this
package. The previous version of EhCache / Hibernate that we were
using seemed ok with this, but after upgrading it caused issues.
Anyway, the entity was in the incorrect package, when I refactored it
and moved it into the correct package then everything worked! So it
was not a bug in Hibernate, just an informative exception that made it
difficult to track this issue down (I basically solved it by complete
fluke).
Hope this helps somebody, but in my case it was a problem with a wrong instrumentation.
I have class 'A' and two child classes 'B' and 'C'. 'A' class has a lazy property and it is instrumented to make the lazy accessing works.
But the mistake was that I didn't instrument the child classes 'B' and 'C', therefore any access to the instrumented property from 'B' and 'C' caused the exception.
When I instrumented 'B' and 'C', the problem went away.

Categories

Resources