Если вы хотите сохранить значение Java Enum в DB в качестве имени перечисления, то драйвер Mongo поддерживает это. Например, если у вас есть перечисление
public enum ProcessType { CONVERT_ONE_TO_ONE, CONVERT_ONE_TO_MANY; }
и он зарегистрирован у поставщика кодеков mongo как
import org.bson.codecs.pojo.ClassModel; import org.bson.codecs.pojo.PojoCodecProvider; import org.bson.codecs.pojo.PojoCodecProvider.Builder; import com.ps2pdf.models.enums.ProcessType; // Local ... Builder builder =ClassModel classModel = ClassModel.builder(ProcessType.class).build(); builder.register(classModel);
затем, всякий раз, когда вы сохраняете экземпляр класса с типом свойства Process Type в DB, результирующий документ Mongo будет иметь строковое значение CONVERT_ONE_TO_ONE
или CONVERT_ONE_TO_MANY
для этого свойства.
если это все, что вам нужно, то следующее не для вас. В этом случае вы можете следовать Mongo POJO tutorial , чтобы направлять вас.
Ниже приведен способ сохранения значения, связанного с перечислением Java, в MongoDB. Зачем кому-то понадобилось это делать?
- В Java (также TypeScript) существует соглашение об использовании имен в верхнем регистре в перечислениях, которое, вероятно, унаследовано от использования имен в верхнем регистре для констант.
- Я предпочитаю присваивать свойствам объекта значения в нижнем регистре (как это делают многие люди)
- Запретить привязку имени свойства к его значению. Я предпочитаю, чтобы имена переменных были короткими, а присвоенное им значение могло быть любым.
Выше приведено несколько причин сохранения значений перечисления вместо имен в MongoDB.
Еще одним болевым моментом для меня было сравнение декодированных значений Enum во внешнем интерфейсе. Ниже приведено перечисление интерфейса TypeScript для приведенного выше перечисления Java.
export enum WebsocketProcessType { CONVERT_ONE_TO_ONE = 'convert-one-to-one', CONVERT_ONE_TO_MANY = 'convert-one-to-many', }
Если бы мы использовали декодер перечислений по умолчанию, предоставляемый драйвером Mongo Java, то наши значения должны совпадать с именами в Java Enum, что слишком сложно и строго для нас, чтобы писать более читаемый код.
Следуя приведенной ниже инструкции и используя Class Transformer для декодирования данных, отправляемых из серверной части, вы сможете легко сопоставлять классы Java с классами TypeScript(js).
Реализация
Шаги:
- Создайте и зарегистрируйте поставщика кодеков в реестре Mongocode, который Mongo использует для определения того, какой Enumdecoder использовать значение Java Enum
- Создайте и зарегистрируйте декодер перечисления для
Типа процесса
- Создайте и зарегистрируйте перечисление в базе данных
Я сделаю некоторые классы универсальными, так как это можно использовать для декодирования всех любых перечислений.
Создайте поставщика кодеков
Я не буду предоставлять импорт, так как у вас должен быть драйвер Mongo Java, а с современными IDE вы можете автоматически импортировать весь импорт.
public class EnumCodecProvider implements CodecProvider { @Override publicCodec get(Class clazz, CodecRegistry registry) { if (clazz == ProcessType.class) { return (Codec ) new ProcessTypeCodec(); } return null; // Don't throw here, this tells Mongo this provider doesn't provide a decoder for the requested clazz } }
Это довольно просто. Монго декодер, вызовите get
метод поставщика, чтобы получить декодер для класса, который он не знает, как декодировать. Когда он вызывает .... получить(ProcessType.class , МонгоРегисты)
|/| мы вернем наш
ProcessTypeCodec , который знает, как декодировать
ProcessType
CodecRegistry pojoCodecRegistry = fromRegistries(MongoClient.getDefaultCodecRegistry(), CodecRegistries.fromRegistries( CodecRegistries.fromProviders(new EnumCodecProvider()) ), ); MongoClientOptions options = MongoClientOptions.builder().codecRegistry(pojoCodecRegistry).build(); // Register above option with the MongoClient
Вышеизложенное регистрирует Поставщик кода перечисления
в реестре mongo.
Создайте кодек Enum для кодирования/декодирования нашего Enum
Я создал абстрактный декодер, чтобы поместить весь общий код, необходимый для декодирования нашего перечисления, чтобы избежать дублирования кода
abstract class AbstractCodec> implements Codec { public AbstractCodec() { } @Override final public void encode(final BsonWriter writer, final T value, final EncoderContext encoderContext) { String val = ((Enum) value).toString(); writer.writeString(val); } @Override final public T decode(final BsonReader reader, final DecoderContext decoderContext) { try { String value = reader.readString(); Method method = getEncoderClass().getDeclaredMethod("fromValue", String.class); T enumName = (T) method.invoke(null, value); return enumName; }catch(Exception e) { try { String value = reader.readString(); Method method = getEncoderClass().getDeclaredMethod("getDefaultValue"); T storageType = (T) method.invoke(null, value); return storageType; } catch (Exception e1) { e1.printStackTrace(); } e.printStackTrace(); } return null; } public abstract Class getEncoderClass(); }
Обратите внимание, что мы вызываем toString
в приведенном выше методе encode
. Этот метод toString
должен быть реализован в классе Process Type
Enum, чтобы предоставить значение имени перечисления.
В методе decode
мы вызываем fromValue
и getDefaultValue
| /
в нашем ProcessType
Enum, чтобы получить имя перечисления, связанное с определенным значением, хранящимся в базе данных. Да, вы должны использовать отражение Java для выполнения метода над объектом класса типа T. Если вам не нравится использовать отражение, вы можете поместить класс decode в
Подводя итог, когда декодер получает запрос со строковым значением, т.е. "convert-one-to-one"
, мы получаем имя класса, связанное с этим кодеком, и вызываем статический метод из Value
, чтобы получить имя перечисления, соответствующее строковому значению.
Ниже приведен Кодек типа процесса
.
public class ProcessTypeCodec extends AbstractCodec{ public ProcessTypeCodec() { super(); } @Override public Class getEncoderClass() { return ProcessType.class; } }
Это просто позволит Mongo узнать класс, который этот кодек может кодировать/декодировать.
Реализовать и зарегистрировать перечисление типов процессов
public enum ProcessType { CONVERT_ONE_TO_ONE("convert-one-to-one"), CONVERT_ONE_TO_MANY("convert-one-to-many"); private String value; private static final MapENUM_MAP; static { Map map = new HashMap (); for (ProcessType instance : ProcessType.values()) { map.put(instance.value(), instance); } ENUM_MAP = Collections.unmodifiableMap(map); } ProcessType(String type) { this.value = type; } public String value() { return this.value; } public static ProcessType fromValue(String value) { return ENUM_MAP.get(value); } /** * Used by the Mongo codec * * @return */ public static ProcessType getDefaultValue() { return CONVERT_ONE_TO_ONE; } /** * Required to properly convert Java Enum name to value. * Value is used by front-end and usually uses
* 1. lowercase
* 2. dashes instead of underscores
*/ @Override public String toString() { return this.value; } }
ENUM_MAP предназначен только для ускорения процесса. Это позволяет нам, декодеру, преобразовать строку в имя перечисления за O(1) временную сложность. По умолчанию вы предпочитаете, я использовал здесь имя перечисления, но обычно это null
.
Смотрите выше для регистрации классов в реестре классов Mongo.
Наш PS2PDF Video Compressor принимает некоторые дополнения в качестве Enum для заполнения аргумента команды, необходимого для FFMPEG для сжатия или преобразования видеофайлов. Например, у нас есть перечисление выходного расширения на интерфейсе
export enum OutputExtension { MP4 = '.mp4', WEBM = '.webm' }
и на серверной части
public enum OutputExtension { MP4(".mp4"), WEBM(".webm") // ... rest of the code similar to above ProcessType Enum }
когда мы сохраняем аргумент командной строки, сгенерированный из TypeScript, в DB в документе, он сохраняет фактическое значение, которое мы хотим, т.е. .mp4
расширение в DB. На серверной части наш декодер правильно сопоставляет это значение с соответствующим Java Enum. Когда мы хотим использовать это для создания команды FFMPEG, мы можем фактически использовать значение Enum напрямую. т.е.
class Request { // Sample class that deals with request document stored in DB OutputExtension outoutExtenstion; } Listcmd = List.of("ffmpeg", ..., "-o", Request.outoutExtenstion); // This generates % ffmpeg ... -o .mp4
Надеюсь, это поможет вам написать более читаемый код. Если вы обнаружите какие-либо ошибки в этом документе, пожалуйста, дайте мне знать, чтобы исправить их.
Оригинал: “https://dev.to/harithay/better-way-to-store-enum-values-in-mongodb-49de”