LoginSignup
0
0

More than 3 years have passed since last update.

DB上でTimestamp型のカラムはSqlResultSetMappingするとjava.util.Date型にマッピングされる件

Last updated at Posted at 2021-01-29

DB検索結果がオブジェクトにマッピングされない

SpringbootでNativeQueryでDBにアクセスする時、Entityと素直にマッピングされない結果が欲しかったため、以下の方法で独自クラスにマッピング定義をして結果を格納するようにしました。

  • 結果セット格納用POJO
ForMapping.java
@Data
@AllArgsConstructor
public class ForMapping {
    private Long id,
    private String name,
    private Timestamp created
}

※コンストラクタやsetter/getterはlombokでやってます。

  • Entityクラス
SomeEntity.java
@SqlResultSetMapping(name = "MappingDef", classes =
{
    @ConstructorResult(targetClass = ForMapping.class, columns =
    {
        @ColumnResult(name = "id", type = Long.class),
        @ColumnResult(name = "name", type = String.class),
        @ColumnResult(name = "created", type = Timestamp.class),
    })
})

テーブル上は、idはlong、nameはTEXT、createdはTIMESTAMP型だったので、それぞれ対応するJavaのクラスを型に指定してマッピングを試みます。

これでSQLを実行して結果を取得しようとした所、結果が1件も取得できませんでした。地道にデバッグしてみると、SQLの実行自体は成功していましたが、結果セットのPOJOへのマッピングのあたりで失敗しているようでした。こんなエラーメッセージが。

Could not locate appropriate constructor on class

エラーメッセージはHibernateの以下の部分で出ていることが分かりました。やはり、SQLの結果セットをPOJOにマッピングするところのようです。

ConstructorResultColumnProcessor.java
private static Constructor resolveConstructor(Class targetClass, List<Type> types) {
    for ( Constructor constructor : targetClass.getConstructors() ) {
        final Class[] argumentTypes = constructor.getParameterTypes();
        if ( argumentTypes.length != types.size() ) {
            continue;
        }

        boolean allMatched = true;
        for ( int i = 0; i < argumentTypes.length; i++ ) {
            if ( ! areAssignmentCompatible( argumentTypes[i], types.get( i ).getReturnedClass() ) ) {
                allMatched = false;
                break;
            }
        }
        if ( !allMatched ) {
            continue;
        }

        return constructor;
    }

    throw new IllegalArgumentException( "Could not locate appropriate constructor on class : " + targetClass.getName() );
}

ソース
https://github.com/hibernate/hibernate-orm/blob/5881b88173d5d8727f8e4aec064751107f430da4/hibernate-core/src/main/java/org/hibernate/loader/custom/ConstructorResultColumnProcessor.java#L71

原因はマッピング定義の型誤り

デバッグで分かりましたが原因は単純で、createdという項目をjava.sql.Timestamp型で指定しているのがNGだったようです。これにより、マッピングしようとしてもマッチするコンストラクタが見つからん!ということで、先のエラーメッセージでした。

公式の情報が見つけられなかったのですが、ネイティブクエリの結果セットをマッピングする時にDB上のTIMESTAMP型をjava.util.Dateにマッピングする、という情報を以下URL内で見つけました。

(参考)
https://stackoverflow.com/questions/24160817/getting-error-could-not-locate-appropriate-constructor-on-class

マッピングの定義部分とPOJOの型をjava.util.Dateに変更したところ、無事結果を取得できるようになりました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0