001package org.conqat.lib.commons.serialization.utils; 002 003import java.io.IOException; 004import java.util.function.Function; 005 006import org.conqat.lib.commons.assertion.CCSMAssert; 007import org.conqat.lib.commons.serialization.SerializedEntityPool; 008import org.conqat.lib.commons.serialization.classes.SerializedBooleanField; 009import org.conqat.lib.commons.serialization.classes.SerializedClass; 010import org.conqat.lib.commons.serialization.classes.SerializedFieldBase; 011import org.conqat.lib.commons.serialization.classes.SerializedLongField; 012import org.conqat.lib.commons.serialization.classes.SerializedObjectField; 013import org.conqat.lib.commons.serialization.objects.SerializedObject; 014import org.conqat.lib.commons.serialization.objects.SerializedStringObject; 015 016/** 017 * Utility class to consistently migrate field names of a 018 * {@link SerializedClass} with their corresponding field values in all 019 * {@link SerializedObject} of the {@link SerializedClass}. 020 */ 021public class SerializedClassFieldMigrator { 022 023 private final SerializedEntityPool entityPool; 024 025 public SerializedClassFieldMigrator(SerializedEntityPool entityPool) { 026 this.entityPool = entityPool; 027 } 028 029 /** 030 * Renames the field of the {@link SerializedClass} and adjusts the 031 * corresponding field values in all {@link SerializedObject}s of the 032 * {@link SerializedClass}. 033 */ 034 public void renameField(String serializedClassName, String oldFieldName, String newFieldName) { 035 SerializedClass serializedClass = entityPool.findClass(serializedClassName); 036 037 if (serializedClass == null) { 038 return; 039 } 040 041 SerializedFieldBase field = serializedClass.getField(oldFieldName); 042 043 // Can happen in case migrations occur across multiple file system versions with 044 // one migration to add the field being missing. 045 if (field != null) { 046 field.setName(newFieldName); 047 } 048 } 049 050 /** 051 * Updates the {@link String} value of a field with type {@link String} 052 * according to the field updater function. 053 */ 054 public void updateStringFieldValue(String serializedClassName, String fieldName, 055 Function<String, String> fieldValueUpdater) throws IOException { 056 SerializedClass serializedClass = entityPool.findClass(serializedClassName); 057 058 if (serializedClass == null) { 059 return; 060 } 061 062 for (SerializedObject serializedObject : SerializedEntityUtils.findInstancesOf(serializedClass, entityPool)) { 063 int stringObjectHandle = (int) serializedObject.getFieldValue(fieldName); 064 String oldValue = entityPool.getEntity(stringObjectHandle, SerializedStringObject.class).getValue(); 065 String newValue = fieldValueUpdater.apply(oldValue); 066 067 serializedObject.setFieldValue(fieldName, new SerializedStringObject(newValue, entityPool).getHandle()); 068 } 069 } 070 071 /** 072 * Adds a new {@link Boolean} field with a default value set in all 073 * {@link SerializedObject}s of the {@link SerializedClass}. The field can't 074 * exist yet. 075 */ 076 public void addBooleanField(String serializedClassName, String fieldName, boolean defaultValue) throws IOException { 077 addField(serializedClassName, fieldName, new SerializedBooleanField(fieldName), defaultValue); 078 } 079 080 081 /** 082 * Adds a new long integer field with a default value set in all 083 * {@link SerializedObject}s of the {@link SerializedClass}. The field can't 084 * exist yet. 085 */ 086 public void addLongField(String serializedClassName, String fieldName, long defaultValue) throws IOException { 087 addField(serializedClassName, fieldName, new SerializedLongField(fieldName), defaultValue); 088 } 089 090 /** 091 * Adds a new {@link String} field with a default value set in all 092 * {@link SerializedObject}s of the {@link SerializedClass}. The field can't 093 * exist yet. 094 */ 095 public void addStringField(String serializedClassName, String fieldName, String defaultValue) throws IOException { 096 addField(serializedClassName, fieldName, 097 new SerializedObjectField(fieldName, 098 SerializedObjectField.createJvmNotationFromPlainClassName(String.class.getName())), 099 new SerializedStringObject(defaultValue, entityPool).getHandle()); 100 } 101 102 private void addField(String serializedClassName, String fieldName, SerializedFieldBase serializedField, 103 Object defaultValue) throws IOException { 104 SerializedClass serializedClass = entityPool.findClass(serializedClassName); 105 106 if (serializedClass == null) { 107 return; 108 } 109 110 CCSMAssert.isTrue(serializedClass.getField(fieldName) == null, 111 () -> "Can't add the already existing field " + fieldName + " to class " + serializedClassName); 112 serializedClass.addField(serializedField); 113 114 for (SerializedObject entity : SerializedEntityUtils.findInstancesOf(serializedClass, entityPool)) { 115 entity.setFieldValue(fieldName, defaultValue); 116 } 117 } 118}