Archiv pro 23. April 2007

Hibernate Synchronizer - pozor na UserType

Při čtení článku Schéma databáze – používáme hibernate mě napadlo, abych napsal o jednom problému, který souvisí s generováním POJOs z mapovacích souborů pomocí Hibernate Synchronizeru v případě používání vlastních typů (UserTypes).

Hibernate umožňuje psaní vlastních typů – takzvaných UserTypes.Mohou být buď jednoduché (skalární – s jednou vlastností) – typ UserType nebo kompozitní – CompositeUserType (více vlastností).

Ukažme si na příkladu použití kompozitního UserTypu:

package cz.vavru.sample.hibernate;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Currency;

import net.sf.hibernate.CompositeUserType;
import net.sf.hibernate.Hibernate;
import net.sf.hibernate.engine.SessionImplementor;
import net.sf.hibernate.type.Type;
import cz.vavru.sample.hibernate.MonetaryAmount;

public class MonetaryAmountType implements CompositeUserType {

        public Class returnedClass() {
                return MonetaryAmount.class;
        }

        ...

        public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session,
                        Object owner) throws SQLException {

                double value = resultSet.getDouble(names[0]);
                if (resultSet.wasNull())
                        return null;
                Currency currency = Currency.getInstance(resultSet.getString(names[1]));
                return new MonetaryAmount(new Double(value), currency);
        }

        public void nullSafeSet(PreparedStatement statement, Object value, int index,
                        SessionImplementor session) throws SQLException {

                if (value == null) {
                        statement.setNull(index, Hibernate.BIG_DECIMAL.sqlType());
                        statement.setNull(index + 1, Hibernate.CURRENCY.sqlType());
                } else {
                        MonetaryAmount amount = (MonetaryAmount) value;
                        String currencyCode = amount.getCurrency().getCurrencyCode();
                        statement.setDouble(index, amount.getValue().doubleValue());
                        statement.setString(index + 1, currencyCode);
                }
        }

        ...
}

Příslušný doménový objekt MonetaryAmount vypadá následovně:

package cz.vavru.sample.hibernate;

import java.io.Serializable;
import java.util.Currency;
import java.util.Iterator;

public class MonetaryAmount implements Serializable {
        private static final long serialVersionUID = Long.MIN_VALUE * 34;
        private Double value;
        private final Currency currency;

        public MonetaryAmount(Currency currency) {
                value = new Double(0d);
                this.currency = currency;
        }

        public MonetaryAmount(BigDecimal bigDecimal, Currency currency) {
                this.value = new Double(bigDecimal.doubleValue());
                this.currency = currency;
        }

        public MonetaryAmount(Double value, Currency currency) {
                this.value = value;
                this.currency = currency;
        }

        public Currency getCurrency() {
                return currency;
        }

        public Double getValue() {
                return value;
        }

        public void setValue(Double value) {
                this.value = value;
        }

        public boolean equals(Object o) {
                if (this == o)
                        return true;
                if (!(o instanceof MonetaryAmount))
                        return false;

                final MonetaryAmount monetaryAmount = (MonetaryAmount) o;

                if (!currency.equals(monetaryAmount.currency))
                        return false;
                if (value != monetaryAmount.value)
                        return false;

                return true;
        }

        public int hashCode() {
                int result;
                result = 29 * value.intValue() + currency.hashCode();
                return result;
        }

        public String toString() {
                return "Value: '" + getValue() + "', " + "Currency: '" + getCurrency() + "'";
        }
}

A ukázka využití v mapovacím souboru jiného doménového objektu, který MonetaryAmount používá:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >

<hibernate-mapping>
        <class name="cz.vavru.sample.hibernate.MyEntity"
                table="ccg_pg_yearly_settings" >

                <id name="id" type="java.lang.Integer" column="id">
                        <generator class="increment" />
                </id>

                ...

                <property name="budget" not-null="false"
                        type="cz.vavru.sample.hibernate.MonetaryAmountType">
                        <column name="budget_amount" />
                        <column name="budget_currency" />
                </property>

        </class>
</hibernate-mapping>

Kód, který Hibernate Synchronizer vygeneruje nesprávně používá pro vlastnost budget typ MonetaryAmountU­serType místo správného MonetaryAmount.

package cz.vavru.sample.hibernate;

public class MyEntity implements Serializable {
        ...
        private cz.vavru.sample.hibernate.MonetaryAmountType budget;
        public cz.vavru.sample.hibernate.MonetaryAmountType getBudget () {
                return budget;
        }

        public void setBudget (cz.vavru.sample.hibernate.MonetaryAmountType budget) {
                this.budget = budget;
        }
        ...
}

Správný kód je tedy:

package cz.vavru.sample.hibernate;

public class MyEntity implements Serializable {
        ...
        private cz.vavru.sample.hibernate.MonetaryAmount budget;
        public cz.vavru.sample.hibernate.MonetaryAmount getBudget () {
                return budget;
        }

        public void setBudget (cz.vavru.sample.hibernate.MonetaryAmount budget) {
                this.budget = budget;
        }
        ...
}

Přiznám se, že mi odhlaní tohoto problému zabralo asi hodinu.

Odkazy

Celý článek 2 komentářů 23. April 2007


Kalendář

April 2007
M T W T F S S
« Mar   May »
 1
2345678
9101112131415
16171819202122
23242526272829
30  

Články podle měsíců

Kategorie

Locations of visitors to this page