From c71d9f75565a822882b32d0f0f67330658b85ca0 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Wed, 1 Jan 2025 22:00:17 +0100 Subject: [PATCH] Prevent class cast exception on `returnedClass()` --- .../hibernate/MigrateUserType.java | 6 +- .../hibernate/MigrateUserTypeTest.java | 472 ++++++++++++------ 2 files changed, 328 insertions(+), 150 deletions(-) diff --git a/src/main/java/org/openrewrite/hibernate/MigrateUserType.java b/src/main/java/org/openrewrite/hibernate/MigrateUserType.java index e3086c0..6a10f43 100644 --- a/src/main/java/org/openrewrite/hibernate/MigrateUserType.java +++ b/src/main/java/org/openrewrite/hibernate/MigrateUserType.java @@ -97,7 +97,11 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, At @Override public J.Return visitReturn(J.Return _return, AtomicReference ref) { - ref.set((J.FieldAccess) _return.getExpression()); + Expression expression = _return.getExpression(); + if (expression instanceof J.FieldAccess && + "class".equals(((J.FieldAccess) expression).getSimpleName())) { + ref.set((J.FieldAccess) expression); + } return _return; } }.visitNonNull(cd, reference); diff --git a/src/test/java/org/openrewrite/hibernate/MigrateUserTypeTest.java b/src/test/java/org/openrewrite/hibernate/MigrateUserTypeTest.java index 4601d49..33b337e 100644 --- a/src/test/java/org/openrewrite/hibernate/MigrateUserTypeTest.java +++ b/src/test/java/org/openrewrite/hibernate/MigrateUserTypeTest.java @@ -41,157 +41,331 @@ void shouldMigrateUserType() { rewriteRun( java( """ - import org.hibernate.HibernateException; - import org.hibernate.engine.spi.SharedSessionContractImplementor; - import org.hibernate.usertype.UserType; - - import java.io.Serializable; - import java.math.BigDecimal; - import java.sql.PreparedStatement; - import java.sql.ResultSet; - import java.sql.SQLException; - import java.sql.Types; - import java.util.Objects; - - public class BigDecimalAsString implements UserType { - - @Override - public int[] sqlTypes() { - return new int[]{Types.VARCHAR}; - } - - @Override - public Class returnedClass() { - return BigDecimal.class; - } - - @Override - public boolean equals(Object x, Object y) { - return Objects.equals(x, y); - } - - @Override - public int hashCode(Object x) { - return Objects.hashCode(x); - } - - @Override - public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws SQLException { - String string = rs.getString(names[0]); - return string == null || rs.wasNull() ? null : new BigDecimal(string); - } - - @Override - public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws SQLException { - if (value == null) { - st.setNull(index, Types.VARCHAR); - } else { - st.setString(index, value.toString()); - } - } - - @Override - public Object deepCopy(Object value1) { - return value1; - } - - @Override - public boolean isMutable() { - return false; - } - - @Override - public Serializable disassemble(Object value) { - return (BigDecimal) value; - } - - @Override - public Object assemble(Serializable cached, Object owner) { - return cached; - } - - @Override - public Object replace(Object original, Object target, Object owner) { - return original; - } - } - """, + import org.hibernate.HibernateException; + import org.hibernate.engine.spi.SharedSessionContractImplementor; + import org.hibernate.usertype.UserType; + + import java.io.Serializable; + import java.math.BigDecimal; + import java.sql.PreparedStatement; + import java.sql.ResultSet; + import java.sql.SQLException; + import java.sql.Types; + import java.util.Objects; + + public class BigDecimalAsString implements UserType { + + @Override + public int[] sqlTypes() { + return new int[]{Types.VARCHAR}; + } + + @Override + public Class returnedClass() { + return BigDecimal.class; + } + + @Override + public boolean equals(Object x, Object y) { + return Objects.equals(x, y); + } + + @Override + public int hashCode(Object x) { + return Objects.hashCode(x); + } + + @Override + public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws SQLException { + String string = rs.getString(names[0]); + return string == null || rs.wasNull() ? null : new BigDecimal(string); + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws SQLException { + if (value == null) { + st.setNull(index, Types.VARCHAR); + } else { + st.setString(index, value.toString()); + } + } + + @Override + public Object deepCopy(Object value1) { + return value1; + } + + @Override + public boolean isMutable() { + return false; + } + + @Override + public Serializable disassemble(Object value) { + return (BigDecimal) value; + } + + @Override + public Object assemble(Serializable cached, Object owner) { + return cached; + } + + @Override + public Object replace(Object original, Object target, Object owner) { + return original; + } + } + """, """ - import org.hibernate.HibernateException; - import org.hibernate.engine.spi.SharedSessionContractImplementor; - import org.hibernate.usertype.UserType; - - import java.io.Serializable; - import java.math.BigDecimal; - import java.sql.PreparedStatement; - import java.sql.ResultSet; - import java.sql.SQLException; - import java.sql.Types; - import java.util.Objects; - - public class BigDecimalAsString implements UserType { - - @Override - public int getSqlType() { - return Types.VARCHAR; - } - - @Override - public Class returnedClass() { - return BigDecimal.class; - } - - @Override - public boolean equals(BigDecimal x, BigDecimal y) { - return Objects.equals(x, y); - } - - @Override - public int hashCode(BigDecimal x) { - return Objects.hashCode(x); - } - - @Override - public BigDecimal nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner) throws SQLException { - String string = rs.getString(position); - return string == null || rs.wasNull() ? null : new BigDecimal(string); - } - - @Override - public void nullSafeSet(PreparedStatement st, BigDecimal value, int index, SharedSessionContractImplementor session) throws SQLException { - if (value == null) { - st.setNull(index, Types.VARCHAR); - } else { - st.setString(index, value.toString()); - } - } - - @Override - public BigDecimal deepCopy(BigDecimal value1) { - return value1; - } - - @Override - public boolean isMutable() { - return false; - } - - @Override - public Serializable disassemble(BigDecimal value) { - return value; - } - - @Override - public BigDecimal assemble(Serializable cached, Object owner) { - return (BigDecimal) cached; - } - - @Override - public BigDecimal replace(BigDecimal original, BigDecimal target, Object owner) { - return original; - } - } + import org.hibernate.HibernateException; + import org.hibernate.engine.spi.SharedSessionContractImplementor; + import org.hibernate.usertype.UserType; + + import java.io.Serializable; + import java.math.BigDecimal; + import java.sql.PreparedStatement; + import java.sql.ResultSet; + import java.sql.SQLException; + import java.sql.Types; + import java.util.Objects; + + public class BigDecimalAsString implements UserType { + + @Override + public int getSqlType() { + return Types.VARCHAR; + } + + @Override + public Class returnedClass() { + return BigDecimal.class; + } + + @Override + public boolean equals(BigDecimal x, BigDecimal y) { + return Objects.equals(x, y); + } + + @Override + public int hashCode(BigDecimal x) { + return Objects.hashCode(x); + } + + @Override + public BigDecimal nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner) throws SQLException { + String string = rs.getString(position); + return string == null || rs.wasNull() ? null : new BigDecimal(string); + } + + @Override + public void nullSafeSet(PreparedStatement st, BigDecimal value, int index, SharedSessionContractImplementor session) throws SQLException { + if (value == null) { + st.setNull(index, Types.VARCHAR); + } else { + st.setString(index, value.toString()); + } + } + + @Override + public BigDecimal deepCopy(BigDecimal value1) { + return value1; + } + + @Override + public boolean isMutable() { + return false; + } + + @Override + public Serializable disassemble(BigDecimal value) { + return value; + } + + @Override + public BigDecimal assemble(Serializable cached, Object owner) { + return (BigDecimal) cached; + } + + @Override + public BigDecimal replace(BigDecimal original, BigDecimal target, Object owner) { + return original; + } + } + """ + ) + ); + } + + @Test + void requireReturnedTypeClass() { + //language=java + rewriteRun( + java( """ + import org.hibernate.HibernateException; + import org.hibernate.engine.spi.SharedSessionContractImplementor; + import org.hibernate.usertype.UserType; + + import java.io.Serializable; + import java.math.BigDecimal; + import java.sql.PreparedStatement; + import java.sql.ResultSet; + import java.sql.SQLException; + import java.sql.Types; + import java.util.Objects; + + public class BigDecimalAsString implements UserType { + + Class returnedClass = BigDecimal.class; + + @Override + public int[] sqlTypes() { + return new int[]{Types.VARCHAR}; + } + + @Override + public Class returnedClass() { + return returnedClass; // Can not yet be migrated, as we can't determine the type of the returned class + } + + @Override + public boolean equals(Object x, Object y) { + return Objects.equals(x, y); + } + + @Override + public int hashCode(Object x) { + return Objects.hashCode(x); + } + + @Override + public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws SQLException { + String string = rs.getString(names[0]); + return string == null || rs.wasNull() ? null : new BigDecimal(string); + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws SQLException { + if (value == null) { + st.setNull(index, Types.VARCHAR); + } else { + st.setString(index, value.toString()); + } + } + + @Override + public Object deepCopy(Object value1) { + return value1; + } + + @Override + public boolean isMutable() { + return false; + } + + @Override + public Serializable disassemble(Object value) { + return (BigDecimal) value; + } + + @Override + public Object assemble(Serializable cached, Object owner) { + return cached; + } + + @Override + public Object replace(Object original, Object target, Object owner) { + return original; + } + } + """ + ) + ); + } + + @Test + void requireReturnedTypeClassWithThis() { + //language=java + rewriteRun( + java( + """ + import org.hibernate.HibernateException; + import org.hibernate.engine.spi.SharedSessionContractImplementor; + import org.hibernate.usertype.UserType; + + import java.io.Serializable; + import java.math.BigDecimal; + import java.sql.PreparedStatement; + import java.sql.ResultSet; + import java.sql.SQLException; + import java.sql.Types; + import java.util.Objects; + + public class BigDecimalAsString implements UserType { + + Class returnedClass = BigDecimal.class; + + @Override + public int[] sqlTypes() { + return new int[]{Types.VARCHAR}; + } + + @Override + public Class returnedClass() { + return this.returnedClass; // Can not yet be migrated, as we can't determine the type of the returned class + } + + @Override + public boolean equals(Object x, Object y) { + return Objects.equals(x, y); + } + + @Override + public int hashCode(Object x) { + return Objects.hashCode(x); + } + + @Override + public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws SQLException { + String string = rs.getString(names[0]); + return string == null || rs.wasNull() ? null : new BigDecimal(string); + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws SQLException { + if (value == null) { + st.setNull(index, Types.VARCHAR); + } else { + st.setString(index, value.toString()); + } + } + + @Override + public Object deepCopy(Object value1) { + return value1; + } + + @Override + public boolean isMutable() { + return false; + } + + @Override + public Serializable disassemble(Object value) { + return (BigDecimal) value; + } + + @Override + public Object assemble(Serializable cached, Object owner) { + return cached; + } + + @Override + public Object replace(Object original, Object target, Object owner) { + return original; + } + } + """ ) ); }