I have AOP aspect for counting times some service was called:
#Aspect
#Component
public class CounterAspect {
private Map<Integer, Integer> gettingEventStatistics = new HashMap<>();
#Pointcut("execution(Event EventService+.getById(Integer))")
private void gettingEvent() {}
#AfterReturning(pointcut = "gettingEvent()", returning = "retVal")
public void countGettingEvent(JoinPoint joinPoint, Object retVal) {
Integer id = (Integer) joinPoint.getArgs()[0];
if (id != null && retVal != null) {
Integer currentCounterValue = gettingEventStatistics.get(id);
gettingEventStatistics.put(id, currentCounterValue == null ? 1 : currentCounterValue + 1);
}
}
}
How could I store such an information in DB using Hibernate?
I've made the following solution - created entity for stats
#Entity
public class GettingEventsStats {
#Id
private Integer eventId;
private Integer gettingCounter;
//getters, setters, etc.
injected DAO delegate in my aspect with such a functionality:
#Repository
public class HibernateStatsDao implements StatsDao {
#Autowired
private SessionFactory sessionFactory;
#Override
public GettingEventsStats getGettingEventStats(Integer eventId) {
return sessionFactory.getCurrentSession().get(GettingEventsStats.class, eventId);
}
#Override
public void createGettingEventCounter(Integer eventId) {
GettingEventsStats gettingEventsStats = new GettingEventsStats();
gettingEventsStats.setEventId(eventId);
gettingEventsStats.setGettingCounter(1);
sessionFactory.getCurrentSession().save(gettingEventsStats);
}
#Override
public void updateGettingEventCounter(Integer eventId) {
GettingEventsStats gettingEventStats = getGettingEventStats(eventId);
gettingEventStats.setGettingCounter(gettingEventStats.getGettingCounter() + 1);
sessionFactory.getCurrentSession().update(gettingEventStats);
}
}
and changed aspect logic to:
#Autowired
private StatsDao statsDao;
#Pointcut("execution(Event EventService+.getById(Integer))")
private void gettingEvent() {}
#AfterReturning(pointcut = "gettingEvent()", returning = "retVal")
public void countGettingEvent(JoinPoint joinPoint, Object retVal) {
Integer eventId = (Integer) joinPoint.getArgs()[0];
if (eventId != null && retVal != null) {
GettingEventsStats gettingEventStats = statsDao.getGettingEventStats(eventId);
if (gettingEventStats == null) {
statsDao.createGettingEventCounter(eventId);
} else {
statsDao.updateGettingEventCounter(eventId);
}
}
}
You are going to save a lot of entries with this method. Better use Dropwizard Metrics which uses Reservoirs for data sampling and custom reporters.
Typically, the metrics are better off exposed through JMX to an APM tool. Or you should use Graphite or Graphana for this purpose.
The simplest way would be parse it to JSON and store as a string. Remember then to increase column max memory size.
Related
I'm currently studying building API's with Spring. I'm working with Spring Validator to validate my input. Here it is my custom validator:
public class NewHoldValidator implements Validator {
private EntityManager manager;
public NewHoldValidator(EntityManager manager) {
this.manager = manager;
}
#Override
public boolean supports(Class<?> clazz) {
return NewHoldRequest.class.isAssignableFrom(clazz);
}
#Override
public void validate(Object target, Errors errors) {
if (errors.hasErrors()) {
return;
}
NewHoldRequest request = (NewHoldRequest) target;
Patron patron = manager.find(Patron.class, request.patronId);
BookInstance bookInstance = manager.find(BookInstance.class, request.bookInstanceId);
Assert.state(patron != null, "Patron does not exists.");
Assert.state(bookInstance != null, "Book instance does not exists.");
if (!bookInstance.acceptToBeHoldTo(patron)) {
errors.reject(null, "This book instance cannot be hold to this patron");
}
if (!request.hasDaysHold()) {
if (!patron.researcher()) {
errors.rejectValue("daysHold", null, "You need to pass a daysHold attribute");
}
}
}
}
And here is my NewHoldRequest class:
public class NewHoldRequest {
#NotNull
public final Long patronId;
#NotNull
public final Long bookInstanceId;
#Positive
#Max(60)
public final Integer daysHold;
public NewHoldRequest(#NotNull Long patronId, #NotNull Long bookInstanceId, #Positive #Max(60) Integer daysHold) {
this.patronId = patronId;
this.bookInstanceId = bookInstanceId;
this.daysHold = daysHold;
}
#Override
public String toString() {
return "NewHoldRequest{" + "patronId=" + patronId + ", bookId=" + bookInstanceId + ", daysHold=" + daysHold + '}';
}
public boolean hasDaysHold() {
return this.daysHold != null;
}
Even if my field "daysHold" is public I still need to create a getter to it so Spring can show the rejected error properly, otherwise, it will throw a NotReadablePropertyException. Is there a way to define that Spring can reject public fields without getters or I will need to add accessor methods to all fields I want to reject?
Here is the message that shows up when my validation is triggered.
org.springframework.beans.NotReadablePropertyException: Invalid property 'daysHold' of bean class [com.api.library.usecases.newhold.NewHoldRequest]: Bean property 'daysHold' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
I'll advise you to use the interface ConstraintValidator. It's a generic's interface, without casting and other problems.
You should create a custom constraint annotation for you it's #NewHoldValid after that implement CustomValidator interface:
#Component
public class NewHoldValidator implements ConstraintValidator<NewHoldValid, NewHoldRequest> {
#Override
public boolean isValid(NewHoldRequest value, ConstraintValidatorContext context) {
if(ANY_CONDITION){
return true;
}else {
return false;
}
}
After that use #NewHoldValid annotation above your NewHoldRequest.
If you'll want to set an error message text which different from default use that:
context.buildConstraintViolationWithTemplate("Your error message").addConstraintViolation();
I need something that seems not so specific but anyway I was unable to come up with nice and sophisticated solution.
Say I have very simple hibernate/jpa entity:
#Entity(name="entity")
public class Type {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#Column(unique = true, nullable = false)
private String name;
#Column(unique = false, nullable = false)
private boolean defaultType;
}
What i need is to somehow annotate defaultType field so only (and exactly) one persisted entity have this value as true. When new entity get persisted with this defaultType as true, the old one (with defaultType=true) entity has to be altered and its defaultType value changed to false. Also if any entity get changed (its defaultType got changed to true), same rule should apply.
As far I know this can be achieved inside business logic (e.g. in DAO layer), with DB trigger or with hibernates interceptor or event (If there is another way, please let me know). I tried with DAO solution but it's kind of bad solution because it can be bypassed and it is really clumsy for such simple operation. DB triggers can not be added with hibernate/jpa annotations (if I am not mistaken) and i am not sure how to make this functionality with hibernate interceptors/events.
So, what is best solution for this problem?
You need use Callback method in JPA, for example PreUpdate or PostUpdate, for instance:
#Entity
#EntityListeners(com.acme.AlertMonitor.class) // set callback method in another class
public class Account {
Long accountId;
Integer balance;
boolean preferred;
#Id
public Long getAccountId() { ... }
...
public Integer getBalance() { ... }
...
#Transient
public boolean isPreferred() { ... }
...
public void deposit(Integer amount) { ... }
public Integer withdraw(Integer amount) throws NSFException {... }
#PreUpdate // callback method in some class
protected void validateCreate() {
if (getBalance() < MIN_REQUIRED_BALANCE)
throw new AccountException("Insufficient balance to open an
account");
}
#PostUpdate // callback method in some class
protected void adjustPreferredStatus() {
preferred =
(getBalance() >= AccountManager.getPreferredStatusLevel());
}
}
// callback method in another class
public class AlertMonitor {
#PreUpdate // callback method in another class
public void updateAccountAlert(Account acct) {
Alerts.sendMarketingInfo(acct.getAccountId(), acct.getBalance());
}
}
Update: About your question, If I undestand what you want, this code may help you:
#Entity(name="entity")
#EntityListeners(com.yourpackage.TypeListner.class)
public class Type {
...
#Column(unique = false, nullable = false)
private boolean defaultType;
}
public class TypeListner {
pivate static Type objectWithTrue = null;
public void init() { // call this method when application is started
List<Type> results = entityManager
.createQuery("from Type", Type.class)
.getResultList();
for(Type type: results) {
if(type.getDefaultType()) {
objectWithTrue = type;
}
}
}
private void changeDefaultType(Type changed) {
if(changed.getDefaultType()) {
if(changed != objectWithTrue && objectWithTrue != null) {
objectWithTrue.setDefaultType(false);
}
objectWithTrue = changed;
}
}
#PostPresist
public void newType(Type changed) {
changeDefaultType(changed);
}
#PostUpdate
public void updateType(Type changed) {
changeDefaultType(changed);
}
#PreRemove
public void removeType(Type changed) {
if(changed.getDefaultType() && objectWithTrue == changed) {
objectWithTrue = null;
}
}
OR
You can use listner #PreUpdate and #PrePresist and every times overwrite all Type objects without store any variable (it isn't so good for perfomance then first example, but more reliable):
#PreUpdate
void updateType(Type changed) {
if(changed.getDefaultType()
List<Type> results = entityManager
.createQuery("from Type", Type.class)
.getResultList();
for(Type type: results) {
if(changed != type && type.getDefaultType()) {
type.setDefaultType(false);
}
}
}
}
I have the following code:
PersonDao.java
#Repository
#Transactional
public class PersonDao implements PersonDaoIface {
Object property;
String order;
#Autowired
private SessionFactory sessionFactory;
public PersonDao() {
}
public PersonDao(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
#SuppressWarnings("unchecked")
#Override
public List<Person> getAll(long first, long count) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Person.class);
this.setPaging(criteria, first, count);
addSort(criteria);
return criteria.list();
}
#Override
public long getAllCount() {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Person.class)
.setProjection(Projections.rowCount());
Long i = (Long) criteria.uniqueResult();
return i;
}
#Override
public List<Person> getByFilter(Person person, int first, int count) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Person.class);
criteria.add(Restrictions.eq("firstName", person.getFirstName()));
criteria.add(Restrictions.eq("lastName", person.getLastName()));
this.setPaging(criteria, first, count);
return criteria.list();
}
#Override
public long getByFilterCount(Person person) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Person.class);
criteria.add(Restrictions.eq("firstName", person.getFirstName()));
criteria.add(Restrictions.eq("lastName", person.getLastName()));
criteria.setProjection(Projections.rowCount());
Long result = (Long) criteria.uniqueResult();
return result;
}
private void setPaging(Criteria criteria, long first, long count) {
criteria.setFirstResult((int) first);
criteria.setMaxResults((int) count);
}
private void addSort(Criteria criteria) {
if (property != null) {
if (order.equalsIgnoreCase(SortOrder.ASCENDING.toString())) {
criteria.addOrder(Order.asc((String)property));
} else {
criteria.addOrder(Order.desc((String)property));
}
}
}
#Override
public void setSort(Object property, String order) {
this.property = property;
this.order = order;
}
}
SortableDataProvider
public class PersonSortableDataProvider extends SortableDataProvider {
private transient PersonDaoIface personDao;
public PersonSortableDataProvider(PersonDaoIface personDao) {
this.personDao = personDao;
}
public PersonSortableDataProvider() {
}
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public Iterator<Person> iterator(long first, long count) {
System.out.println(getSort());
return personDao.getAll(first, count).iterator();
}
#Override
public long size() {
long result = personDao.getAllCount();
return result;
}
#Override
public IModel<Person> model(final Object object) {
return new AbstractReadOnlyModel<Person>() {
#Override
public Person getObject() {
return (Person) object;
}
};
}
}
A panel with a data table using the sortable data provider
public DataDisplayPanel(String id) {
super(id);
List<IColumn> columns = new ArrayList<IColumn>();
columns.add(new PropertyColumn(new Model<String>("First Name"), "firstName"));
columns.add(new PropertyColumn(new Model<String>("Last Name"), "lastName"));
AjaxFallbackDefaultDataTable table = new AjaxFallbackDefaultDataTable("personData", columns,
personSortableDataProvider, 8);
table.addTopToolbar(new HeadersToolbar(table, personSortableDataProvider));
add(table);
}
I have paging done no problem but I am having trouble understanding how to get sorting working with hibernate, I can see how you could do the sorting from the java side of things but given that I could potentially get large data sets back I don't like this idea.
Given my code above does anyone have a way of getting the data table, on click of either first name or last name to then make the same query found in the iterator with the additional order by clause.
You are almost there. You just need an:
addOrder(Order.asc(columnName))
The doc is here.
To anyone that encounters this situation I have the following setup:
hibernate 4, spring 4 and wicket 6
I inject using Spring and it seems wicket and spring get confused if you inject within the SortableDataProvider.
I don't know what exactly happens; when i step over the project I will have a better idea but it appears setSort is not getting set correctly, when i move the Dao class out of sortable data provider and into the page and inject it there, then pass the dao instance into sortable data provider the sorting works correctly.
I am using #CascadeSave to save child object in separate collection.
My Document classes are :
public class FbUserProfile{
#Id
private long id;
#DBRef(lazy=true)
#CascadeSave()
private Set<FacebookFriend> friends;
#DBRef(lazy=true)
#CascadeSave()
private Set<FacebookFriendList> customFriendList;
}
public class FacebookFriend{
#Id
private long id;
private String name;
}
public class FacebookFriendList{
#Id
private long id;
private String name;
private String list_type;
}
I add some object in both friends,customFriendList.
and try to update fbUserProfile object using:
mongoTemplate.save(fbUserProfile);
note: fbUserProfile already exists in db. Now I am updating this
Error Message: Cannot perform cascade save on child object without id set
If I remove #CascadeSave. It works fine for me. How I can Cascade set objects.
I am also using #CascadeSave with other objects. Its working fine but they are not set object.
I found the same tutorials somewhere else: Baeldung's and JavaCodeGeeks (this is the one i've followed)
I've had that same problem, and I could solve it.
It happens when you try to persist a collection. It doesn't matter that the collection's items have the #Id, because the collection itself won't have it. I edited the code in the EventListener's onBeforeConvert to check if the field you're trying to CascadeSave is a collection (in my case a List). If it's a list, you just cycle through it checking each individual item for #Id and saving them.
If it's not a collection you still have to persist them the same way you did before
#Override
public void onBeforeConvert(Object source) {
ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() {
#Override
public void doWith(Field field)
throws IllegalArgumentException, IllegalAccessException {
ReflectionUtils.makeAccessible(field);
if (field.isAnnotationPresent(DBRef.class) && field.isAnnotationPresent(CascadeSave.class)){
final Object fieldValue = field.get(source);
if(fieldValue instanceof List<?>){
for (Object item : (List<?>)fieldValue){
checkNSave(item);
}
}else{
checkNSave(fieldValue);
}
}
}
});
}
private void checkNSave(Object fieldValue){
DbRefFieldCallback callback = new DbRefFieldCallback();
ReflectionUtils.doWithFields(fieldValue.getClass(), callback);
if (!callback.isIdFound()){
throw new MappingException("Oops, something went wrong. Child doesn't have #Id?");
}
mongoOperations.save(fieldValue);
}
The best way to set an ID on the dependent child object is to write a listener class by extending AbstractMongoEventListener class and override the onConvert() method.
public class CustomMongoEventListener extends
AbstractMongoEventListener<Object> {
#Autowired
private MongoOperations mongoOperations;
#Override
public void onBeforeConvert(final Object entity) {
if (entity.id == null || entity.id.isEmpty()) {
entity.id = generateGuid(); //generate random sequence ID
}
public static String generateGuid() {
SecureRandom randomGen = new SecureRandom();
byte[] byteArray = new byte[16];
randomGen.nextBytes(byteArray);
return new Base32().encodeToString(byteArray).substring(0,26);
}
}
Finally register your custom listener in `your configuration file. For annotation approach use the following code to register :
#Bean
public CustomMongoEventListener cascadingMongoEventListener() {
return new CustomMongoEventListener();
}
The above solution works fine incase if you have a list. But we can avoid firing a save query for each element from the list, as it reduces the performance. Here is the solution I have found out of the above code.
#Override
public void onBeforeConvert(BeforeConvertEvent<Object> event) {
Object source = event.getSource();
ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() {
#Override
public void doWith(Field field)
throws IllegalArgumentException, IllegalAccessException {
ReflectionUtils.makeAccessible(field);
if (field.isAnnotationPresent(DBRef.class) && field.isAnnotationPresent(CascadeSave.class)){
final Object fieldValue = field.get(source);
if(fieldValue instanceof List<?>){
for (Object item : (List<?>)fieldValue){
checkNAdd(item);
}
}else{
checkNAdd(fieldValue);
}
mongoOperations.insertAll(documents);
}
}
});
}
private void checkNAdd(Object fieldValue){
DbRefFieldCallback callback = new DbRefFieldCallback();
ReflectionUtils.doWithFields(fieldValue.getClass(), callback);
if (!callback.isIdFound()){
throw new MappingException("Oops, something went wrong. Child doesn't have #Id?");
}
documents.add(fieldValue);
}
Okey I extend the class and it will check if the document is exist if it exist it will update the document else it insert the document:
#Component
class GenericCascadeMongo(
private val mongoTemplate: MongoTemplate
) : AbstractMongoEventListener<Any>() {
override fun onBeforeConvert(event: BeforeConvertEvent<Any?>) {
val source = event.source
?: return
ReflectionUtils.doWithFields(source.javaClass) { field ->
ReflectionUtils.makeAccessible(field)
if (field.isAnnotationPresent(DBRef::class.java) && field.isAnnotationPresent(CascadeSave::class.java)) {
val fieldValue = field[source]
?: return#doWithFields
if (fieldValue is List<*>) {
fieldValue.filterNotNull().forEach {
checkAndSave(it)
}
} else {
checkAndSave(fieldValue)
}
}
}
}
private fun checkAndSave(fieldValue: Any) {
try {
val callback = DbRefFieldCallback(fieldValue)
ReflectionUtils.doWithFields(fieldValue.javaClass, callback)
if (!callback.isIdFound && callback.id == null) {
mongoTemplate.insert(fieldValue)
}
if (callback.id != null) {
val findById = mongoTemplate.exists(Query(Criteria.where(MConst.MONGO_ID).`is`(callback.id)), fieldValue.javaClass)
if (findById) {
mongoTemplate.save(fieldValue)
} else {
mongoTemplate.insert(fieldValue)
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
private class DbRefFieldCallback(val fieldValue: Any?) : FieldCallback {
var isIdFound = false
private set
var id: String? = null
private set
#Throws(IllegalArgumentException::class, IllegalAccessException::class)
override fun doWith(field: Field) {
ReflectionUtils.makeAccessible(field)
if (field.isAnnotationPresent(Id::class.java)) {
isIdFound = true
id = ReflectionUtils.getField(field, fieldValue)?.toString()
}
}
}
}
My web app is using GWT 2.0.2, GXT 2.1.1, Hibernate 3.5-CR1, Javassist 3.11.0 and Gilead 1.3.1 (latest from SVN).
My app was running just fine with GWT 1.7.1 + Gilead 1.2.
I want to take advantage of some of the features of GWT 2.0, and figured I'd upgrade to the latest Gilead in the process. I pointed to the new gwt.xml file in Gilead 1.3. I'm also using the new net.sf.gilead.pojo.gwt.LightEntity instead of net.sf.gilead.pojo.java5.LightEntity.
I have a few Hibernate entities/classes that extend LightEntity (i.e. Question, Form), as well as a few more entities/classes that extend the Question entity. Not sure if it matters, but I'm using InheritanceType.JOINED for the inheritance strategy in the Question entity.
For reference, here's the Question class:
#Entity
#Table(name = "Questions")
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Question extends LightEntity implements IsSerializable,
IFormItem, Comparable<Question> {
private static final long serialVersionUID = 9180458948973980161L;
public static final String FIELD_NAME_PREFIX = "field_"; //$NON-NLS-1$
private static final String REQUIRED_QUESTION = "<span style=\"color: red;\">*</span>"; //$NON-NLS-1$
public static int MIN_WIDTH = 50;
public static int DEFAULT_WIDTH = 200;
public static int MAX_WIDTH = 600;
private int id;
private Integer questionOrder;
private String questionNumber;
protected String questionText;
protected boolean required;
private String toolTip;
protected Integer fieldWidth;
#Id
#GeneratedValue
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public boolean isRequired() {
return this.required;
}
public void setRequired(boolean required) {
this.required = required;
}
public String getToolTip() {
return this.toolTip;
}
public void setToolTip(String toolTip) {
this.toolTip = toolTip;
}
#Column(length = 5000)
#Lob
public String getQuestionText() {
return this.questionText;
}
public void setQuestionText(String pText) {
this.questionText = pText;
}
public Integer getQuestionOrder() {
return this.questionOrder;
}
public void setQuestionOrder(Integer questionOrder) {
this.questionOrder = questionOrder;
}
public String getQuestionNumber() {
return this.questionNumber;
}
public void setQuestionNumber(String questionNumber) {
this.questionNumber = questionNumber;
}
public boolean hasQuestionNumber() {
return getQuestionNumber() != null
&& !getQuestionNumber().trim().isEmpty();
}
public Integer getFieldWidth() {
return this.fieldWidth;
}
public void setFieldWidth(Integer fieldWidth) {
this.fieldWidth = fieldWidth;
}
public Component render(FormPanel formPanel, int order, int questionSpacing) {
final Component c = generateWidget(getId());
if (c instanceof Field<?>) {
final Field<?> field = (Field<?>) c;
field.setLabelSeparator(FormBuilderConstants.EMPTY_TEXT);
field.setValidateOnBlur(true);
field.setAutoValidate(true);
field.setName(FIELD_NAME_PREFIX.concat(String.valueOf(getId())));
if (getToolTip() != null) {
field.setToolTip(getToolTip());
}
final FormData formData;
if (field instanceof SimpleComboBox<?>) {
formData = new FormData();
} else {
if (getFieldWidth() == null) {
field.setAutoWidth(true);
formData = new FormData(FormBuilderConstants.FORM_ANCHOR_SPEC);
} else {
field.setWidth(getFieldWidth().intValue());
field.setAutoWidth(false);
formData = new FormData(getFieldWidth().intValue(), -1);
}
}
final String questionNumber;
if (this.questionNumber != null && !this.questionNumber.isEmpty()) {
questionNumber = this.questionNumber;
} else {
questionNumber = String.valueOf(order);
}
if (this.answerable()) {
String displayQuestionText = questionNumber.concat(". ") //$NON-NLS-1$
.concat(getQuestionText());
if (isRequired()) {
displayQuestionText = displayQuestionText
.concat(REQUIRED_QUESTION);
}
field.setFieldLabel(displayQuestionText);
}
field.setIntStyleAttribute("margin-bottom", questionSpacing); //$NON-NLS-1$
formPanel.add(field, formData);
} else {
formPanel.add(c);
}
return c;
}
protected abstract Component generateWidget(final int id);
public abstract String questionType();
public int compareTo(final Question q) {
return this.questionOrder.intValue() - q.questionOrder.intValue();
}
public boolean answerable() {
return true;
}
}
My app has a startup servlet that creates a Hibernate session factory. In the logs, I get a "duplicate method" error on all of the classes that directly or indirectly extend LightEntity. I wonder if this is an issue with Javassist's handling of inheritance.
16:32:59,616 DEBUG AbstractEntityPersister:2773 - Identity insert: insert into Questions (fieldWidth, questionNumber, questionOrder, questionText, required, toolTip) values (?, ?, ?, ?, ?, ?)
16:32:59,619 ERROR BasicLazyInitializer:165 - Javassist Enhancement failed: com.function1.formbuilder.client.model.Question
java.lang.RuntimeException: duplicate method: getProxyInformation in com.function1.formbuilder.client.model.Question_$$_javassist_5
at javassist.util.proxy.ProxyFactory.createClass3(ProxyFactory.java:344)
at javassist.util.proxy.ProxyFactory.createClass2(ProxyFactory.java:314)
at javassist.util.proxy.ProxyFactory.createClass(ProxyFactory.java:273)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.getProxyFactory(JavassistLazyInitializer.java:162)
at org.hibernate.proxy.pojo.javassist.JavassistProxyFactory.postInstantiate(JavassistProxyFactory.java:66)
at org.hibernate.tuple.entity.PojoEntityTuplizer.buildProxyFactory(PojoEntityTuplizer.java:188)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.<init>(AbstractEntityTuplizer.java:151)
at org.hibernate.tuple.entity.PojoEntityTuplizer.<init>(PojoEntityTuplizer.java:78)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at org.hibernate.tuple.entity.EntityTuplizerFactory.constructTuplizer(EntityTuplizerFactory.java:107)
at org.hibernate.tuple.entity.EntityTuplizerFactory.constructDefaultTuplizer(EntityTuplizerFactory.java:135)
at org.hibernate.tuple.entity.EntityEntityModeToTuplizerMapping.<init>(EntityEntityModeToTuplizerMapping.java:80)
at org.hibernate.tuple.entity.EntityMetamodel.<init>(EntityMetamodel.java:323)
at org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEntityPersister.java:456)
at org.hibernate.persister.entity.JoinedSubclassEntityPersister.<init>(JoinedSubclassEntityPersister.java:113)
at org.hibernate.persister.PersisterFactory.createClassPersister(PersisterFactory.java:87)
at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:267)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1341)
at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:867)
at com.function1.common.F1HibernateUtil.<clinit>(F1HibernateUtil.java:22)
at com.function1.formbuilder.server.StartupServlet.init(StartupServlet.java:26)
Caused by: java.lang.RuntimeException: duplicate method: getProxyInformation in com.function1.formbuilder.client.model.Question_$$_javassist_0
at javassist.util.proxy.ProxyFactory.createClass3(ProxyFactory.java:344)
at javassist.util.proxy.ProxyFactory.createClass2(ProxyFactory.java:314)
at javassist.util.proxy.ProxyFactory.createClass(ProxyFactory.java:273)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.getProxyFactory(JavassistLazyInitializer.java:162)
... 42 more
Caused by: javassist.bytecode.DuplicateMemberException: duplicate method: getProxyInformation in com.function1.formbuilder.client.model.Question_$$_javassist_0
at javassist.bytecode.ClassFile.testExistingMethod(ClassFile.java:593)
at javassist.bytecode.ClassFile.addMethod(ClassFile.java:577)
at javassist.util.proxy.ProxyFactory.override(ProxyFactory.java:658)
at javassist.util.proxy.ProxyFactory.overrideMethods(ProxyFactory.java:632)
at javassist.util.proxy.ProxyFactory.make(ProxyFactory.java:552)
at javassist.util.proxy.ProxyFactory.createClass3(ProxyFactory.java:335)
Any ideas on how to resolve this issue?
As illustrated by ticket HIBERNATE-37, somehow getProxyInformation() gets define twice, possibly with a different return type.
ticket HHH-1938 suggested using cglib instead of JavaAssist as a bytecode enhancer, but I an not sure if this is possible in your configuration.
You must change the value of
hibernate.bytecode.provider=javassist
for
hibernate.bytecode.provider=cglib
in:
<WHERE IS YOUR JBOSS>\server\default\deploy\ejb3.deployer\META-INF\ persistence.properties
And that fixes the problem of duplicated method
(again, this is not your configuration but that could give you an idea where to look)
The new javassist versoin 3.16.1-GA will work with duplicate methods:
https://issues.jboss.org/browse/JASSIST-127
And there were some other similar issues also fixed for 3.16.0-GA
Javassist doesn't allow duplicate methods (allowed by Java5)
https://jira.jboss.org/jira/browse/JASSIST-24
Try removing Comparable<Question> if that is possible.