Динамические перечисления в Spring, или как сохранить Spring от конструкторов?
Является ли "динамическое перечисление" оксюмороном, как "статические переменные"?;-)
Я только в течение короткого времени впитывал весну, и я подозреваю, что я еще не думаю о Spring. Я хотел бы иметь безопасное для типов динамическое перечисление. Я использовал этот шаблон для таких вещей, как события или коды ошибок, где вы хотите разрешить последующим подклассам расширять перечисление. Поскольку "enum" не может быть расширен, у вас остается класс шаблона перечисления. Например (урезанный):
public class EventType {
private String name;
private static HashMap<String, EventType> cache
= new HashMap<String, EventType>();
protected EventType(String name) {
if (cache.containsKey(name)) {
throw new RuntimeException("EventType '" + name + "' already exists!");
} else {
this.name = name;
cache.put(name, this);
}
}
public static AuditEventType parse(String name) {
return cache.get(name);
}
public static final EventType EVENT_START = new AuditEventType("Start");
public static final EventType EVENT_END = new AuditEventType("End");
public static final EventType EVENT_FAIL = new AuditEventType("Fail");
}
Проблемы начинаются, когда я добавляю Spring в микс. Поскольку это всего лишь строка, я пометил EventType как "@Embeddable", а классы, которые его используют, аннотируют этот член как "@Embedded". Казалось, что это прекрасно работает, пока не пришло время для запросов с использованием queryDSL-jpa. DSL попытается преобразовать текст БД в EventType, который затем будет иметь несоответствие типов со строками. То есть я не мог сказать: WHERE EventType = "Start"
, Я справился с этим (не элегантно), сохранив класс с таким полем для хранения его как String и проанализировав его с объектом EventType в получателе. Так что теперь это просто старая строка в отношении JPA.
Теперь я столкнулся с проблемой с сервисным API. У меня есть метод с параметром EventType. Проблема в том, что класс JsonRpcServer пытается преобразовать String в EventType, создав его экземпляр. Это, конечно, бросает "уже существует!" исключение.
Я, вероятно, могу решить эту вторую проблему с @JsonTypeResolver (о которой я сейчас читаю). Но все эти махинации чувствуют себя не так. Это должно быть общей проблемой, и должно быть лучшее решение. Как правильно обращаться с такими классами в Spring? (где это не bean-компонент, действительно, и имеет защищенный конструктор).
(Я опускаю некоторые подробности о некоторых проприетарных библиотеках, которые использует наш код, и которые могут не позволить мне принять ответ типа "О, вы должны вместо этого использовать" X ". Спасибо за понимание".)
1 ответ
Для стороны Spring взгляните на ConversionService. Это позволяет вам регистрировать пользовательские конвертеры. Таким образом, вы должны иметь возможность зарегистрировать свой EventTypeToStringConverter и StringToEventTypeConverter. Они будут иметь "полный" контроль для разрешения от / к вашему типу события.
Для стороны Hibernate может быть решение использовать определенный UserType для вашего EventType, чтобы Hibernate мог сохранять и читать его как значение столбца. (это то, что, как я ожидаю, вам нужно) У меня было похожее требование со статусом для каждой сущности, который я не хотел моделировать как саму сущность. Мне пока не удавалось напрямую использовать строковый параметр в запросе, но существует множество интерфейсов, которые вы могли бы реализовать, скорее всего, есть такой, который позволяет распознавать строки для параметров.