Parent.java 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package me.lortseam.completeconfig.data;
  2. import me.lortseam.completeconfig.api.ConfigContainer;
  3. import me.lortseam.completeconfig.api.ConfigGroup;
  4. import me.lortseam.completeconfig.data.structure.Identifiable;
  5. import me.lortseam.completeconfig.data.structure.StructurePart;
  6. import me.lortseam.completeconfig.data.structure.client.Translatable;
  7. import me.lortseam.completeconfig.exception.IllegalAnnotationTargetException;
  8. import me.lortseam.completeconfig.util.ReflectionUtils;
  9. import org.apache.commons.lang3.ArrayUtils;
  10. import org.spongepowered.configurate.CommentedConfigurationNode;
  11. import java.lang.reflect.InvocationTargetException;
  12. import java.lang.reflect.Modifier;
  13. import java.util.Arrays;
  14. import java.util.Collection;
  15. import java.util.Collections;
  16. import java.util.function.BiConsumer;
  17. import java.util.function.Predicate;
  18. abstract class Parent implements StructurePart, Translatable {
  19. private static <C extends StructurePart & Identifiable> void propagateToChildren(Collection<C> children, CommentedConfigurationNode node, Predicate<CommentedConfigurationNode> childNodeCondition, BiConsumer<C, CommentedConfigurationNode> function) {
  20. for (C child : children) {
  21. CommentedConfigurationNode childNode = node.node(child.getId());
  22. if (!childNodeCondition.test(childNode)) {
  23. continue;
  24. }
  25. function.accept(child, childNode);
  26. }
  27. }
  28. private static <C extends StructurePart & Identifiable> void propagateToChildren(Collection<C> children, CommentedConfigurationNode node, BiConsumer<C, CommentedConfigurationNode> function) {
  29. propagateToChildren(children, node, childNode -> true, function);
  30. }
  31. private final EntrySet entries = new EntrySet(this);
  32. private final ClusterSet clusters = new ClusterSet(this);
  33. public final Collection<Entry> getEntries() {
  34. return Collections.unmodifiableCollection(entries);
  35. }
  36. public final Collection<Cluster> getClusters() {
  37. return Collections.unmodifiableCollection(clusters);
  38. }
  39. final void resolveContainer(ConfigContainer container) {
  40. entries.resolve(container);
  41. for (Class<? extends ConfigContainer> clazz : container.getConfigClasses()) {
  42. resolve(Arrays.stream(clazz.getDeclaredFields()).filter(field -> {
  43. if (field.isAnnotationPresent(ConfigContainer.Transitive.class)) {
  44. if (!ConfigContainer.class.isAssignableFrom(field.getType())) {
  45. throw new IllegalAnnotationTargetException("Transitive field " + field + " must implement " + ConfigContainer.class.getSimpleName());
  46. }
  47. return !Modifier.isStatic(field.getModifiers()) || clazz == container.getClass();
  48. }
  49. return false;
  50. }).map(field -> {
  51. if (!field.canAccess(container)) {
  52. field.setAccessible(true);
  53. }
  54. try {
  55. return (ConfigContainer) field.get(container);
  56. } catch (IllegalAccessException e) {
  57. throw new RuntimeException(e);
  58. }
  59. }).toArray(ConfigContainer[]::new));
  60. Class<?>[] nestedClasses = clazz.getDeclaredClasses();
  61. ArrayUtils.reverse(nestedClasses);
  62. resolve(Arrays.stream(nestedClasses).filter(nestedClass -> {
  63. if (nestedClass.isAnnotationPresent(ConfigContainer.Transitive.class)) {
  64. if (!ConfigContainer.class.isAssignableFrom(nestedClass)) {
  65. throw new IllegalAnnotationTargetException("Transitive " + nestedClass + " must implement " + ConfigContainer.class.getSimpleName());
  66. }
  67. if (!Modifier.isStatic(nestedClass.getModifiers())) {
  68. throw new IllegalAnnotationTargetException("Transitive " + nestedClass + " must be static");
  69. }
  70. return true;
  71. }
  72. return false;
  73. }).map(nestedClass -> {
  74. try {
  75. return (ConfigContainer) ReflectionUtils.instantiateClass(nestedClass);
  76. } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
  77. throw new RuntimeException("Failed to instantiate nested " + nestedClass, e);
  78. }
  79. }).toArray(ConfigContainer[]::new));
  80. }
  81. resolve(container.getTransitives());
  82. }
  83. final void resolve(ConfigContainer... containers) {
  84. for (ConfigContainer container : containers) {
  85. if (container instanceof ConfigGroup) {
  86. clusters.resolve((ConfigGroup) container);
  87. } else {
  88. resolveContainer(container);
  89. }
  90. }
  91. }
  92. @Override
  93. public final void apply(CommentedConfigurationNode node) {
  94. propagateToChildren(entries, node, childNode -> !childNode.isNull(), StructurePart::apply);
  95. propagateToChildren(clusters, node, childNode -> !childNode.isNull(), StructurePart::apply);
  96. }
  97. @Override
  98. public void fetch(CommentedConfigurationNode node) {
  99. propagateToChildren(entries, node, StructurePart::fetch);
  100. propagateToChildren(clusters, node, StructurePart::fetch);
  101. }
  102. final boolean isEmpty() {
  103. return entries.isEmpty() && clusters.isEmpty();
  104. }
  105. }