AnnoMap.java
/*
* SPDX-FileCopyrightText: 2025 kaumei.io
* SPDX-License-Identifier: Apache-2.0
*/
package io.kaumei.jdbc.anno.model;
import io.kaumei.jdbc.anno.ProcessorException;
import io.kaumei.jdbc.anno.ctx.ConfigService;
import io.kaumei.jdbc.anno.ctx.Context;
import org.jspecify.annotations.Nullable;
import javax.lang.model.AnnotatedConstruct;
import javax.lang.model.element.TypeElement;
import java.util.*;
public class AnnoMap {
public static AnnoMap of(Context ctx, AnnotatedConstruct element) {
var anno2value = new HashMap<JavaAnnoType<?>, Object>();
for (var annoMirror : element.getAnnotationMirrors()) {
if (annoMirror.getAnnotationType().asElement() instanceof TypeElement te) { // sanity-check
var anno = ctx.KAUMEI_ANNO.get(te.getQualifiedName());
if (anno != null) {
if (anno2value.put(anno, anno.getAnno(annoMirror)) != null) { // sanity-check
throw new ProcessorException("Duplicate annotation: " + anno); // sanity-check
}
}
}
}
return new AnnoMap(ctx, anno2value);
}
// ------------------------------------------------------------------------
private final Context ctx;
private final Map<JavaAnnoType<?>, Object> anno2value;
private final Set<JavaAnnoType<?>> unused;
private AnnoMap(Context ctx, Map<JavaAnnoType<?>, Object> anno2value) {
this.ctx = ctx;
this.anno2value = anno2value;
this.unused = new HashSet<>(this.anno2value.keySet());
}
@Override
public String toString() {
return anno2value.toString();
}
// ------------------------------------------------------------------------
public void consume(JavaAnnoType<?> anno) {
unused.remove(anno);
}
public <T> @Nullable T getOpt(JavaAnnoType<T> anno) {
var value = this.anno2value.get(anno);
if (value != null) {
unused.remove(anno);
return anno.cast(value);
}
return null;
}
public <T> T get(JavaAnnoType<T> anno, T defaultValue) {
var value = this.anno2value.get(anno);
if (value != null) {
unused.remove(anno);
return anno.cast(value);
}
return defaultValue;
}
public <T> @Nullable T getOpt(ConfigService.Option<T> option) {
var value = this.anno2value.get(option.anno());
if (value != null) {
unused.remove(option.anno());
return option.cast(value);
}
return null;
}
public <T> @Nullable T getIfNotDefault(ConfigService.Option<T> option) {
var value = this.anno2value.get(option.anno());
if (option.isNotDefaultValue(value)) {
unused.remove(option.anno());
return option.cast(value);
}
return null;
}
public <T> @Nullable T getIfDefault(ConfigService.Option<T> option) {
var value = this.anno2value.get(option.anno());
if (option.isDefaultValue(value)) {
unused.remove(option.anno());
return option.cast(value);
}
return null;
}
// ------------------------------------------------------------------------
public boolean hasUnused() {
return !unused.isEmpty();
}
public Set<JavaAnnoType<?>> unused() {
return Collections.unmodifiableSet(unused);
}
// ------------------------------------------------------------------------
public record JdbcEntryPoints(int count,
JavaAnnoType.@Nullable JdbcBatchUpdateRecord batchUpdate,
JavaAnnoType.@Nullable JdbcCallRecord call,
JavaAnnoType.@Nullable JdbcNativeRecord nativeJdbc,
JavaAnnoType.@Nullable JdbcSelectRecord select,
JavaAnnoType.@Nullable JdbcUpdateRecord update) {
}
public JdbcEntryPoints entryPoints() {
int count = 0;
var batchUpdate = this.getOpt(ctx.JDBC_BATCH_UPDATE);
if (batchUpdate != null) {
count++;
}
var call = this.getOpt(ctx.JDBC_CALL);
if (call != null) {
count++;
}
var nativeJdbc = this.getOpt(ctx.JDBC_NATIVE);
if (nativeJdbc != null) {
count++;
}
var select = this.getOpt(ctx.JDBC_SELECT);
if (select != null) {
count++;
}
var update = this.getOpt(ctx.JDBC_UPDATE);
if (update != null) {
count++;
}
return new JdbcEntryPoints(count, batchUpdate, call, nativeJdbc, select, update);
}
}