-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 
Author Message
 Post subject: validation of a persisted map (4.0.1.GA)
PostPosted: Wed Nov 18, 2009 4:31 pm 
Newbie

Joined: Tue Dec 04, 2007 6:24 am
Posts: 13
Hi,

I am trying to validate an entity that holds a Map<K, V> of other persisted entities (just checking wether the map holds some predefined values).
I can validate it "by hand" using validator.validate() and my map is correctly filled at validation time
However when validation framework is called by persistence callbacks, my map is always empty...
I am using Validator 4.0.1.GA and hibernate-core 3.5.0-Beta-2

I tryed to pinpoint the problem and it seems that the map is not touched in the following method of AbstractType during the merge :

Code:
public Object replace(
      Object original, Object target, SessionImplementor session,
      Object owner, Map copyCache, ForeignKeyDirection foreignKeyDirection) throws HibernateException {
   boolean include;
   if ( isAssociationType() ) {
      AssociationType atype = (AssociationType) this;
      include = atype.getForeignKeyDirection()==foreignKeyDirection;
   }
   else {
      include = ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT==foreignKeyDirection;
   }
   return include ? replace(original, target, session, owner, copyCache) : target;
}


I am not sure this should be posted here rather than in the hibernate-core forum so I am trying here first.
Perhaps I am trying to do something not allowed by persistence or validation spec?
Can someone help please?


Top
 Profile  
 
 Post subject: Re: validation of a persisted map (4.0.1.GA)
PostPosted: Mon Nov 23, 2009 3:18 pm 
Hibernate Team
Hibernate Team

Joined: Thu Apr 05, 2007 5:52 am
Posts: 1689
Location: Sweden
Could you provide some more information. How do your annotated classes look like? Which constraint are you using?


Top
 Profile  
 
 Post subject: Re: validation of a persisted map (4.0.1.GA)
PostPosted: Tue Nov 24, 2009 8:48 am 
Newbie

Joined: Tue Dec 04, 2007 6:24 am
Posts: 13
Hi,

Thanks for your answer.
My model is pretty complex so I tried to get rid of everything I assume is irrelevant concerning the problem.
If it is was not enough, I could provide you with the actual classes but there are quite a lot due to several levels of inheritance.
Here are the classes :

The class holding the map
Code:
@Entity
@Table(name = "diagnostic")
public class Diagnostic extends AnnotableObject<DiagnosticAnnotation, DiagnosticAttribute> {
    private static final long serialVersionUID = 3825148115001055028L;
    private Integer version = null;
    protected Map<DiagnosticAttribute, DiagnosticAnnotation> annotations = new HashMap<DiagnosticAttribute, DiagnosticAnnotation>();
   
    @Override
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() {
        return id;
    }

    @Version
    public Integer getVersion() {
        return version;
    }
   
    @Override
    //@DiagnosticMandatoryAnnotations => FAILING ON PERSISTENCE
    @OneToMany(fetch = FetchType.EAGER, mappedBy = "entity", cascade = CascadeType.ALL/*, orphanRemoval = true*/)
    @MapKey(name = "attribute")
    public Map<DiagnosticAttribute, DiagnosticAnnotation> getAnnotations() {
        return annotations;
    }
   
    public void setVersion(Integer version) {
        this.version = version;
    }
   
    @Override
    public void setAnnotations(Map<DiagnosticAttribute, DiagnosticAnnotation> annotations) {
        this.annotations = annotations;
    }

    @Override
    public void addAnnotation(DiagnosticAnnotation annotation) {
       annotation.setEntity(this);
       annotations.put(annotation.getAttribute(), annotation);
    }

    @Override
    public void removeAnnotation(String name) {
       DiagnosticAnnotation a = annotations.remove(new DiagnosticFreeAttribute(name));
       a.setEntity(null);
    }
}

The class used as a key for the map
Code:
@Entity
@Table(name = "attribute", uniqueConstraints = @UniqueConstraint(columnNames = {"type", "name"}))
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
public class DiagnosticAttribute<ENTITY extends Annotable<?, ?>> extends BaseObject implements Serializable {
    private static final long serialVersionUID = -328834888742499071L;
    protected String name;
       
    @Override
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() {
        return id;
    }

    @Column(length = 100, nullable = false)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

The class used as a value for the map
Code:
@Entity
@Table(name = "eav_diagnostic")
public class DiagnosticAnnotation extends Annotation<Diagnostic, DiagnosticAttribute> implements Serializable {
    private static final long serialVersionUID = -5180580885061582423L;
    private Diagnostic entity = null;
    private DiagnosticAttribute attribute = null;

    @Override
    @NotNull
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(nullable = false, updatable = false)
    public Diagnostic getEntity() {
   return super.getEntity();
    }
   
    @Override
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(nullable = false, updatable = false)
    public DiagnosticAttribute getAttribute() {
        return super.getAttribute();
    }
   
    @Override
    @NotNull
    @Valid
    @OneToOne(cascade = CascadeType.ALL, optional = false)
    @JoinColumn(nullable = false, updatable = true)
    public AnnotationValue<? extends DiagnosticAttribute> getValue() {
        return value;
    }
}

Here are the validation stuff :
Code:
@Target( { METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = DiagnosticMandatoryAnnotationsValidator.class)
@Documented
public @interface DiagnosticMandatoryAnnotations {
    Class<? extends Payload>[] payload() default {};
    Class<?>[] groups() default {};
    String message() default "Il manque des donnĂ©es pour ce diagnostic";
    String[] mandatoryNames() default { "diagnostic1", "diagnostic2", "dateDiagnostic2" };
}

Code:
public class DiagnosticMandatoryAnnotationsValidator implements ConstraintValidator<DiagnosticMandatoryAnnotations, Map<DiagnosticAttribute, DiagnosticAnnotation>> {
    private String[] mandatoryNames;

    public void initialize(DiagnosticMandatoryAnnotations constraintAnnotation) {
        mandatoryNames = constraintAnnotation.mandatoryNames();
    }

    public boolean isValid(Map<DiagnosticAttribute, DiagnosticAnnotation> annotationMap, ConstraintValidatorContext constraintContext) {
       for (String name: mandatoryNames) {
           if (!annotationMap.containsKey(new DiagnosticFreeAttribute(name))){
              return false;
           }
        }
       return true;       
    }
}

Hope it helps to understand the problem.
Thanks


Top
 Profile  
 
 Post subject: Re: validation of a persisted map (4.0.1.GA)
PostPosted: Wed Nov 25, 2009 8:38 am 
Hibernate Team
Hibernate Team

Joined: Thu Apr 05, 2007 5:52 am
Posts: 1689
Location: Sweden
That's a lot of code. Any chance you can condense this into a unit test we can run?
Does the application behave as expected when you don't use validation? Are you sure your session management is correct?

--Hardy


Top
 Profile  
 
 Post subject: Re: validation of a persisted map (4.0.1.GA)
PostPosted: Wed Nov 25, 2009 10:16 am 
Newbie

Joined: Tue Dec 04, 2007 6:24 am
Posts: 13
The application behaves as expected as long as I dont use validation constraints on this map.

Concerning my session management, I am using spring 3.0.0.RC2 and below is the config file for my DAO unit test (my hibernate.cfg.xml simply contains the <mapping> stuff for my entities).

Code:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:tx="http://www.springframework.org/schema/tx"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
   default-lazy-init="true">

   <!-- Enable stereotype support -->
   <context:annotation-config />
   <context:component-scan base-package="com.creps.core" />
   
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:applicationContext.properties</value>
            </list>
        </property>
    </bean>
   
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
      <property name="driverClass" value="${jdbc.driver}" />
      <property name="jdbcUrl" value="${jdbc.url}" />
      <property name="user" value="${jdbc.username}" />
      <property name="password" value="${jdbc.password}" />
      <property name="initialPoolSize" value="10" />
      <property name="minPoolSize" value="5" />
      <property name="maxPoolSize" value="25" />
      <property name="acquireRetryAttempts" value="10" />
      <property name="acquireIncrement" value="5" />
      <property name="idleConnectionTestPeriod" value="3600" />
      <property name="maxIdleTime" value="10800" />
      <property name="maxConnectionAge" value="14400" />
      <property name="preferredTestQuery" value="SELECT 1;" />
      <property name="testConnectionOnCheckin" value="false" />
   </bean>
         
   <bean id="auditedSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
      <property name="dataSource" ref="dataSource" />
      <property name="configLocation" value="classpath:hibernate.cfg.xml" />
      <property name="hibernateProperties">
         <value>
            hibernate.dialect=${hibernate.dialect}
            hibernate.query.substitutions=true 'Y', false 'N'
            hibernate.cache.use_second_level_cache=true
            hibernate.cache.provider_class=net.sf.ehcache.hibernate.SingletonEhCacheProvider
            hibernate.hbm2ddl.auto=update
            hibernate.c3p0.acquire_increment=5
            hibernate.c3p0.idle_test_period=3600
            hibernate.c3p0.timeout=10800
            hibernate.c3p0.max_size=25
            hibernate.c3p0.min_size=1
            hibernate.show_sql=false
         </value>
      </property>
       <property name="eventListeners">
            <map>
                <entry key="pre-insert" value-ref="beanValidationEventListener" />
                <entry key="pre-update" value-ref="beanValidationEventListener" />
            </map>
        </property>
   </bean>
   
   <bean id="validationFactory" class="javax.validation.Validation" factory-method="buildDefaultValidatorFactory" />
   
    <bean id="beanValidationEventListener" class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener">
        <constructor-arg index="0" ref="validationFactory" />
        <constructor-arg index="1">
            <props/>
        </constructor-arg>
    </bean>
   
   <bean id="transactionManager"
      class="org.springframework.orm.hibernate3.HibernateTransactionManager">
      <property name="sessionFactory" ref="auditedSessionFactory" />
   </bean>

</beans>

If nothing looks suspicious to you with my session management, I could write a small maven project with a unit test to reproduce it.
It will be a pain but I already sold this feature to customer ;)

--thogau


Top
 Profile  
 
 Post subject: Re: validation of a persisted map (4.0.1.GA)
PostPosted: Sat Dec 05, 2009 10:18 am 
Hibernate Team
Hibernate Team

Joined: Thu Apr 05, 2007 5:52 am
Posts: 1689
Location: Sweden
Sorry for the late reply. Do you have still the same problem. The config file looks ok. Were you able to extract a test case?

--Hardy


Top
 Profile  
 
 Post subject: Re: validation of a persisted map (4.0.1.GA)
PostPosted: Thu Jan 21, 2010 8:13 am 
Newbie

Joined: Tue Dec 04, 2007 6:24 am
Posts: 13
I am even more sorry for the even later reply.

I made a small project (maven & eclipse) to reproduce the problem with some unit tests.
I created a JIRA issue and attached the project to it : http://opensource.atlassian.com/project ... e/BVAL-197

Thanks


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.