Java2JdbcResolver.java
/*
* SPDX-FileCopyrightText: 2025 kaumei.io
* SPDX-License-Identifier: Apache-2.0
*/
package io.kaumei.jdbc.anno.model;
import io.kaumei.jdbc.anno.ctx.Context;
import io.kaumei.jdbc.anno.msg.JdbcMsg;
import io.kaumei.jdbc.anno.msg.Msg;
import io.kaumei.jdbc.anno.store.SearchKey;
import org.jspecify.annotations.Nullable;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import static java.util.Objects.requireNonNull;
record Java2JdbcResolver(Context ctx) {
enum Kind {ARRAY, LIST, RECORD}
record Single(OptionalFlag optional, SearchKey searchRequest) {
}
Msg.Result<Single> single(VariableElement element) {
var optional = ctx.optionalFlag(element, element.asType());
if (optional.isOptionalType()) {
return Msg.result(JdbcMsg.OPTIONAL_TYPE_NOT_SUPPORTED);
}
var converterName = ctx.JDBC_CONVERTER_NAME.getAnnoOpt(element);
if (converterName != null && converterName.isBlankName()) {
return Msg.result(JdbcMsg.annotationValueMustNotBeBlank("@JdbcConverterName"));
}
return Msg.result(new Java2JdbcResolver.Single(optional, SearchKey.of(ctx, element)));
}
// ------------------------------------------------------------------------
static final class Values {
private final Kind kind;
private final OptionalFlag optional;
private final @Nullable SearchKey searchRequest;
private final @Nullable OptionalFlag cmpOptional;
Values(Kind kind, OptionalFlag optional,
@Nullable SearchKey searchRequest,
@Nullable OptionalFlag cmpOptional) {
this.kind = kind;
this.optional = optional;
this.searchRequest = searchRequest;
this.cmpOptional = cmpOptional;
}
public Kind kind() {
return kind;
}
public OptionalFlag optional() {
return optional;
}
public SearchKey searchRequest() {
return requireNonNull(searchRequest);
}
public OptionalFlag cmpOptional() {
return requireNonNull(cmpOptional);
}
}
Msg.Result<Values> values(VariableElement element) {
var mirror = element.asType();
var optional = ctx.optionalFlag(element, mirror);
if (optional.isOptionalType()) {
return Msg.result(JdbcMsg.OPTIONAL_TYPE_NOT_SUPPORTED);
} else if (optional.isNullable()) {
return Msg.result(JdbcMsg.NULLABLE_NOT_SUPPORTED);
}
var converterName = ctx.JDBC_CONVERTER_NAME.getAnnoOpt(element);
if (converterName != null) {
if (converterName.isBlankName()) {
return Msg.result(JdbcMsg.annotationValueMustNotBeBlank("@JdbcConverterName"));
}
return Msg.result(JdbcMsg.JDBC_CONVERTER_NAME_NOT_SUPPORTED);
}
Kind kind;
TypeMirror cmp;
if (mirror instanceof ArrayType arrayType) {
kind = Kind.ARRAY;
cmp = arrayType.getComponentType();
} else if (ctx.JAVA_List.isSameType(mirror)) {
var declared = (DeclaredType) mirror;
if (declared.getTypeArguments().size() != 1) {
return Msg.result(JdbcMsg.JAVA_TO_JDBC_RESOLVER_LIST_REQUIRES_COMPONENT_TYPE);
}
kind = Kind.LIST;
cmp = declared.getTypeArguments().get(0);
} else if (mirror instanceof DeclaredType declared
&& declared.asElement().getKind() == ElementKind.RECORD) {
return Msg.result(new Java2JdbcResolver.Values(Kind.RECORD, optional, null, null));
} else {
return Msg.result(JdbcMsg.JAVA_TO_JDBC_RESOLVER_VALUES_UNSUPPORTED_TYPES);
}
var cmpOptional = ctx.optionalFlag(element, cmp);
if (cmpOptional.isOptionalType()) {
return Msg.result(JdbcMsg.OPTIONAL_TYPE_NOT_SUPPORTED);
}
return Msg.result(new Java2JdbcResolver.Values(kind, optional, SearchKey.of(cmp, ConverterNameDV.unnamed()),
cmpOptional));
}
}