views:

120

answers:

1

We have tables with legacy columns where SpecialStrings are stored. These SpecialStrings can't be NULL and they instead equal to some SPECIAL_UNICODE_NULL.

So to send an entity back to a client via JAX-WS we have to either implement the whole Entity wrapper for sending it instead of Entity or to add convert logic explicitly to Entity get methods.

What we would like to do is to use our own @LegacyString annotation.

@Column(name="A_LEGACY_COLUMN")
@LegacyString
public String oneOfThenLegacyColumn;

And then in the default Entity listener @PostLoad we would transform all of the @LegacyString fields to regular string by using appropriate transformation.

But the problem with such solution is that after post load modifications entity is considered as changed and the Entity Manager will try to update it to the database. Of course I can use @PreUpdate method to revert changes back. But I am not sure that this will prevent Entity from real update.

So the question is: How to change Entity Bean values View via own annotations?

P.S. I dig a little about ClassLoader and I am going to consider variant with adding changes in the load time. But I can't find an reasonable example with Application Server class loader case.

+1  A: 

You can handle special cases like this in Hibernate by creating your own implementation of org.hibernate.usertype.UserType.

public class SpecialStringUserType implements UserType {

  private static final int[] SQL_TYPES = { Types.VARCHAR };

  public int[] sqlTypes() {
    return SQL_TYPES;
  }

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

  public boolean equals(Object x, Object y) 
      throws HibernateException {
    if (x == y) {
      return true;
    } else if (x == null || y == null) {
      return false;
    } else {
      return x.equals(y);
    }
  }

  public Object nullSafeGet(ResultSet resultSet, 
      String[] names, Object owner)
      throws HibernateException, SQLException {
    String result = resultSet.getString(names[0]);
    if ("SPECIAL_UNICODE_NULL".equals( result )) {
       return null;
    }
    return result;
  }

  public void nullSafeSet(PreparedStatement statement, 
      Object value, int index)
      throws HibernateException, SQLException {
    if (value == null) {
      statement.setString(index, "SPECIAL_UNICODE_NULL");
    } else {
      statement.setString(index, value);
    }
  }

  public Object deepCopy(Object value) throws HibernateException {
    return value;
  }

  public boolean isMutable() {
    return false;
  }
}

Instead of using your own @LegacyString annotation do the following:

@Column(name="A_LEGACY_COLUMN")
@Type( type = "SpecialStringUserType" )
public String oneOfThenLegacyColumn;
mtpettyp
I am going to check this today. It looks pretty. What about same thing but with TopLink? Can it be somehow cross vender?
Mykola Golubyev
Unfortunately this functionality isn't available in the current JPA spec but most JPA providers have extensions to add this. For TopLink you need to implement oracle.toplink.mappings.converters.Converter I believe. It looks more complicated to add it to your Entity, take a look at http://markmail.org/message/lc47ejjlmsflkxdn
mtpettyp