Annotation based mapping more prone to circular dependencies compared to .hbm.xml?

Hi there, in our legacy project we’ve been using a module based architecture with .hbm.xml mapping. Each module is structured like this

image

For each entity, we have an interface providing it’s methods and we have an implementation. The interface is stored in common, the implementation in business. Let’s assume we have a table question and a table option. a question can have multiple options, an option is assigned to one question.

So far, a typical mapping could have looked like this:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.cl.moda.srm.qs.business.impl.SrmQsQuestionVOImpl" table="srm_t_question" proxy="com.cl.myApp.srm.qs.common.business.SrmQsQuestionVO">
    <id name="rowguid" column="rowguid" type="java.lang.Long">
        <generator class="sequence">
            <param name="sequence_name">srm_t_question_rowguid_seq</param>
        </generator>
    </id>
        
    <set name="options" table="srm_t_question_option" lazy="false" cascade="all-delete-orphan" inverse="true" fetch="select">
        <key column="qo_fk_question_id" not-null="true" />
        <one-to-many entity-name="com.cl.moda.srm.qs.business.impl.SrmQsQuestionOptionVOImpl" />
    </set>
  </class>
</hibernate-mapping>

The corresponding VO interface and implementation would look like this:


package com.cl.moda.srm.qs.business.impl;

public class SrmQsQuestionVOImpl implements SrmQsQuestionVO {

    private Long rowguid;

    private java.util.Set<SrmQsQuestionOptionVO> options;
  
}

package com.cl.moda.srm.qs.common.business;

public interface SrmQsQuestionVO {

    Long getRowguid();

    void setRowguid (Long rowguid);

    java.util.Set<SrmQsQuestionOptionVO> getOptions();

    void setOptions(java.util.Set<SrmQsQuestionOptionVO> options);

}

Notice that in SrmQsQuestionVO we do not reference the implementation class (SrmQsQuestionVO). That means, that we do not have to provide a dependency from business package to common package in pom.xml

Now when using annotation-mapping, the same would look like this:

package com.cl.moda.srm.qs.business.impl;

@Entity
@Proxy(proxyClass = SrmQsQuestionVO.class)
public class SrmQsQuestionVOImpl implements SrmQsQuestionVO {

    private Long rowguid;

    @OneToMany(mappedBy = "question")
    private java.util.Set<SrmQsQuestionOptionVOImpl> options;

// Getters and setters omitted
}

The corresponding interface would have to look similar:

package com.cl.moda.srm.qs.common.business;

public class SrmQsQuestionVO implements SrmQsQuestionVO {

    Long getRowguid();
    void setRowguid(Long rowguid);
    
    java.util.Set<SrmQsQuestionOptionVOImpl> getOptions;
    void setOptions(java.util.Set<SrmQsQuestionOptionVOImpl> options);

}

Now the problem with this setup is that when using annotation-based mapping I am no longer able to map options as java.util.Set<SrmQsQuestionOptionVO>, but I have to resort to java.util.Set<SrmQsQuestionOptionVOImpl> instead so that the mappedBy attribute recognizes the question member in the SrmQsQuestionOptionVOImpl, which is of course not available in the interface.

That means that suddenly the common package that has my interface needs a dependency to the business package and the business package needs a dependency to the common package, which causes circular dependencies and is not able to be resolved by maven.

Is there any good-practice to solve these kind of problems?

Does the following not work for you?

public class SrmQsQuestionVO implements SrmQsQuestionVO {
    Long getRowguid();
    void setRowguid(Long rowguid);
    
    java.util.Set<? extends SrmQsQuestionOptionVO> getOptions;
    void setOptions(java.util.Set<? extends SrmQsQuestionOptionVO> options);
}
@Entity
@Proxy(proxyClass = SrmQsQuestionVO.class)
public class SrmQsQuestionVOImpl implements SrmQsQuestionVO {

    private Long rowguid;

    @OneToMany(mappedBy = "question")
    private java.util.Set<SrmQsQuestionOptionVOImpl> options;

// Getters and setters omitted
}

After some preliminary tests, this seems to work fine. Many thanks!