Generate Embeddable property from Database for two given columns


#1

Hi,

I’m using hibernate tool in a maven project to generate Hibernate Entities from a database. I have two columns named code and year which repeat itself in several tables and hold the exact same values. I wanted to have those two columns in an embeddable named CodeYear and then use it in the entities having the columns.

I look at the NameStrategy, the custom exporter and the JDBCDialect and I have a hard time to see where I can hook myself to replace the two columns code Year for the embeddable.

Any hints on how to achieve this?


#2

Hi @plum117,

Unfortunately generating embeddable is currently not possible with Hibernate Tools. It would be a useful addition though albeit not an easy one. Firstly there would need to be a possibility to define embedded entities in reveng.xml and secondly the column elements would need to have an attribute indicating if and to which embedded entity they belong. Lastly the generation process (and templates) would have to be adapted. If you need this addition, feel free to open an issue in our JIRA tracker (https://hibernate.atlassian.net/projects/HBX) and of course it would be really nice if you would contribute it…

Cheers,
Koen


#3

Hi,

If I find some enough free time to try it I will suggest something.

Meanwhile, in a tricky way, I was able to change two column (‘CODE’ and ‘YEAR’) for one given classname using a Custom Strategy:

  1. Overriding columnToHibernateTypeName to change the type of the column CODE for the desired embeddable.
  2. Excluding the column YEAR. For this one I tried to override excludeColumn but since my embeddable was used in composite key then it was throwing some exception. I had to actually extends EntityPOJOClass and ComponentPOJOClass to override the getAllPropertiesIterator and remove the column property Year.
  3. Add manually the @Embeddable (next step to code)

Code to achieve 1 and 2:

    @Override
    public String columnToHibernateTypeName(
        TableIdentifier table,
        String columnName,
        int sqlType,
        int length,
        int precision,
        int scale,
        boolean nullable,
        boolean generatedIdentifier) {

        if (columnName.equals("CODE")) {
            return "com.model.embeddable.CodeYear";
        }

        return super.columnToHibernateTypeName(table, columnName, sqlType, length, precision, scale, nullable,
            generatedIdentifier);
    }
  1. In CustomComponentPOJOClass and CustomEntityPOJOClass override getAllPropertiesIterator to exclude Year
    @Override
    @SuppressWarnings("unchecked")
    public Iterator<Property> getAllPropertiesIterator() {

        List<Property> properties = new ArrayList<Property>();
        Iterator<Property> itr = this.clazz.getPropertyIterator();

        itr.forEachRemaining(c -> properties.add(c));

        // Excluding Year for property to render since Code will be replace by CodeYear
        return properties.stream().filter(c -> !c.getName().equals("Year")).collect(Collectors.toList())
            .iterator();
    }

Note: For the Custom Strategy to use the extended classes of ComponentPOJOClass and EntityPOJOClass, you need to also extends Cfg2JavaTool and

public class CustomCfg2JavaTool
    extends Cfg2JavaTool {

    public CustomCfg2JavaTool() {

        super();
    }

    @Override
    public POJOClass getPOJOClass(
        Component comp) {

        return new CustomComponentPOJOClass(comp, this);
    }

    @Override
    public POJOClass getPOJOClass(
        PersistentClass pComp) {

        return new CustomEntityPOJOClass(pComp, this);
    }
}

In Hbm2JavaCustomExporter you specify to use your CustomCustomCfg2JavaTool and the workaround to make sure to use you CustomComponentPOJOClass

public class Hbm2JavaCustomExporter
    extends POJOExporter {

    public Hbm2JavaCustomExporter() {

        super();
        this.log.info("Using " + this.getClass().getName());
    }

    public Hbm2JavaCustomExporter(
        Configuration pCfg,
        File pOutputdir) {

        super(pCfg, pOutputdir);
        this.log.info("Using " + this.getClass().getName());
    }

    
    @Override
    public Cfg2JavaTool getCfg2JavaTool() {
    
        return new CustomCfg2JavaTool();
    }
   
    // Workaround since GenericExporter do not wrap POJOClass with the one specify by the Cfg2JavaTool
    protected void exportComponent(Map<String, Object> additionalContext, POJOClass element) {
        exportPOJO(additionalContext, this.getCfg2JavaTool().getPOJOClass((Component) element.getDecoratedObject()));     
    }

}