EntryMap.java 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. package me.lortseam.completeconfig.data;
  2. import com.google.common.base.CaseFormat;
  3. import me.lortseam.completeconfig.ConfigMap;
  4. import me.lortseam.completeconfig.api.ConfigEntry;
  5. import me.lortseam.completeconfig.api.ConfigEntryContainer;
  6. import me.lortseam.completeconfig.api.ConfigEntryListener;
  7. import me.lortseam.completeconfig.exception.IllegalAnnotationParameterException;
  8. import me.lortseam.completeconfig.exception.IllegalAnnotationTargetException;
  9. import me.lortseam.completeconfig.exception.IllegalModifierException;
  10. import me.lortseam.completeconfig.exception.IllegalReturnTypeException;
  11. import org.apache.commons.lang3.StringUtils;
  12. import java.lang.reflect.Modifier;
  13. import java.util.ArrayList;
  14. import java.util.Arrays;
  15. import java.util.List;
  16. import java.util.stream.Collectors;
  17. public class EntryMap extends ConfigMap<Entry> {
  18. EntryMap(String modTranslationKey) {
  19. super(modTranslationKey);
  20. }
  21. void fill(Collection parent, ConfigEntryContainer container) {
  22. List<Entry> containerEntries = new ArrayList<>();
  23. for (Class<? extends ConfigEntryContainer> clazz : container.getConfigClasses()) {
  24. Arrays.stream(clazz.getDeclaredMethods()).filter(method -> !Modifier.isStatic(method.getModifiers()) && method.isAnnotationPresent(ConfigEntryListener.class)).forEach(method -> {
  25. ConfigEntryListener listener = method.getDeclaredAnnotation(ConfigEntryListener.class);
  26. String fieldName = listener.value();
  27. if (fieldName.equals("")) {
  28. if (!method.getName().startsWith("set") || method.getName().equals("set")) {
  29. throw new IllegalAnnotationParameterException("Could not detect field name for listener method " + method + ", please provide it inside the annotation");
  30. }
  31. fieldName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, method.getName().replaceFirst("set", ""));
  32. }
  33. Class<? extends ConfigEntryContainer> fieldClass = listener.container();
  34. if (fieldClass == ConfigEntryContainer.class) {
  35. fieldClass = clazz;
  36. }
  37. if (method.getParameterCount() != 1) {
  38. throw new IllegalArgumentException("Listener method " + method + " has wrong number of parameters");
  39. }
  40. Entry<?> entry = Entry.of(parent, fieldName, fieldClass);
  41. if (method.getParameterTypes()[0] != entry.getType()) {
  42. throw new IllegalArgumentException("Listener method " + method + " has wrong argument type");
  43. }
  44. if (method.getReturnType() != Void.TYPE) {
  45. throw new IllegalReturnTypeException("Listener method " + method + " may not return a type other than void");
  46. }
  47. if (!method.isAccessible()) {
  48. method.setAccessible(true);
  49. }
  50. entry.addListener(method, container);
  51. });
  52. List<Entry> clazzEntries = new ArrayList<>();
  53. Arrays.stream(clazz.getDeclaredFields()).filter(field -> {
  54. if (Modifier.isStatic(field.getModifiers())) {
  55. return false;
  56. }
  57. if (container.isConfigPOJO()) {
  58. return !ConfigEntryContainer.class.isAssignableFrom(field.getType()) && !field.isAnnotationPresent(ConfigEntry.Ignore.class);
  59. }
  60. return field.isAnnotationPresent(ConfigEntry.class);
  61. }).forEach(field -> {
  62. if (Modifier.isFinal(field.getModifiers())) {
  63. throw new IllegalModifierException("Entry field " + field + " must not be final");
  64. }
  65. if (!field.isAccessible()) {
  66. field.setAccessible(true);
  67. }
  68. Entry<?> entry = Entry.of(parent, field, container);
  69. if (field.isAnnotationPresent(ConfigEntry.class)) {
  70. ConfigEntry entryAnnotation = field.getDeclaredAnnotation(ConfigEntry.class);
  71. String id = entryAnnotation.value();
  72. if (!StringUtils.isBlank(id)) {
  73. entry.setCustomID(id);
  74. }
  75. String customTranslationKey = entryAnnotation.customTranslationKey();
  76. if (!StringUtils.isBlank(customTranslationKey)) {
  77. entry.setCustomTranslationKey(modTranslationKey + "." + customTranslationKey);
  78. }
  79. String[] customTooltipKeys = entryAnnotation.customTooltipKeys();
  80. if (customTooltipKeys.length > 0) {
  81. for (String key : customTooltipKeys) {
  82. if (StringUtils.isBlank(key)) {
  83. throw new IllegalAnnotationParameterException("Tooltip key(s) of entry field " + field + " must not be blank");
  84. }
  85. }
  86. entry.setCustomTooltipTranslationKeys(Arrays.stream(customTooltipKeys).map(key -> modTranslationKey + "." + key).toArray(String[]::new));
  87. }
  88. entry.setForceUpdate(entryAnnotation.forceUpdate());
  89. entry.setRequiresRestart(entryAnnotation.requiresRestart());
  90. }
  91. if (field.isAnnotationPresent(ConfigEntry.Bounded.Integer.class)) {
  92. if (field.getType() != int.class && field.getType() != Integer.class) {
  93. throw new IllegalAnnotationTargetException("Cannot apply Integer bound to non Integer field " + field);
  94. }
  95. ConfigEntry.Bounded.Integer bounds = field.getDeclaredAnnotation(ConfigEntry.Bounded.Integer.class);
  96. entry.setBounds(bounds.min(), bounds.max(), bounds.slider());
  97. }
  98. if (field.isAnnotationPresent(ConfigEntry.Bounded.Long.class)) {
  99. if (field.getType() != long.class && field.getType() != Long.class) {
  100. throw new IllegalAnnotationTargetException("Cannot apply Long bound to non Long field " + field);
  101. }
  102. ConfigEntry.Bounded.Long bounds = field.getDeclaredAnnotation(ConfigEntry.Bounded.Long.class);
  103. entry.setBounds(bounds.min(), bounds.max(), bounds.slider());
  104. }
  105. if (field.isAnnotationPresent(ConfigEntry.Bounded.Float.class)) {
  106. if (field.getType() != float.class && field.getType() != Float.class) {
  107. throw new IllegalAnnotationTargetException("Cannot apply Float bound to non Float field " + field);
  108. }
  109. ConfigEntry.Bounded.Float bounds = field.getDeclaredAnnotation(ConfigEntry.Bounded.Float.class);
  110. entry.setBounds(bounds.min(), bounds.max(), false);
  111. }
  112. if (field.isAnnotationPresent(ConfigEntry.Bounded.Double.class)) {
  113. if (field.getType() != double.class && field.getType() != Double.class) {
  114. throw new IllegalAnnotationTargetException("Cannot apply Double bound to non Double field " + field);
  115. }
  116. ConfigEntry.Bounded.Double bounds = field.getDeclaredAnnotation(ConfigEntry.Bounded.Double.class);
  117. entry.setBounds(bounds.min(), bounds.max(), false);
  118. }
  119. if (Enum.class.isAssignableFrom(field.getType())) {
  120. if (field.isAnnotationPresent(ConfigEntry.EnumOptions.class)) {
  121. entry.setEnumOptions(field.getDeclaredAnnotation(ConfigEntry.EnumOptions.class).displayType());
  122. } else {
  123. entry.setEnumOptions(EnumOptions.DisplayType.getDefault());
  124. }
  125. } else if (field.isAnnotationPresent(ConfigEntry.EnumOptions.class)) {
  126. throw new IllegalAnnotationTargetException("Cannot apply enum options to non enum field " + field);
  127. }
  128. clazzEntries.add(entry);
  129. });
  130. containerEntries.addAll(0, clazzEntries);
  131. }
  132. putAll(containerEntries.stream().collect(Collectors.toMap(Entry::getID, entry -> entry)));
  133. }
  134. }