001/*
002 * Configurate
003 * Copyright (C) zml and Configurate contributors
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.spongepowered.configurate.examples;
018
019import static java.util.Objects.requireNonNull;
020
021import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
022import org.checkerframework.checker.nullness.qual.Nullable;
023import org.spongepowered.configurate.CommentedConfigurationNode;
024import org.spongepowered.configurate.ConfigurateException;
025import org.spongepowered.configurate.ConfigurationNode;
026import org.spongepowered.configurate.ScopedConfigurationNode;
027import org.spongepowered.configurate.hocon.HoconConfigurationLoader;
028import org.spongepowered.configurate.objectmapping.ConfigSerializable;
029import org.spongepowered.configurate.objectmapping.ObjectMapper;
030import org.spongepowered.configurate.objectmapping.meta.Comment;
031import org.spongepowered.configurate.serialize.SerializationException;
032
033import java.nio.file.Path;
034import java.nio.file.Paths;
035import java.util.ArrayList;
036import java.util.List;
037import java.util.UUID;
038import java.util.regex.Pattern;
039
040/**
041 * Example of how to use the ObjectMapper for a simple read-only configuration.
042 *
043 * <p>Error handling is not considered in this example, but for a fully fledged
044 * application it would be essential.</p>
045 */
046public final class ObjectMapperExample {
047
048    private ObjectMapperExample() {}
049
050    public static void main(final String[] args) throws ConfigurateException {
051        final Path file = Paths.get(args[0]);
052        final HoconConfigurationLoader loader = HoconConfigurationLoader.builder()
053                .defaultOptions(opts -> opts.shouldCopyDefaults(true))
054                .path(file) // or setUrl(), or setFile(), or setSource/Sink
055                .build();
056
057        final CommentedConfigurationNode node = loader.load(); // Load from file
058        final MyConfiguration config = MyConfiguration.loadFrom(node); // Populate object
059
060        // Do whatever actions with the configuration, then...
061        config.itemName("Steve");
062
063        config.saveTo(node); // Update the backing node
064        loader.save(node); // Write to the original file
065    }
066
067    @ConfigSerializable
068    static class MyConfiguration {
069
070        private static final ObjectMapper<MyConfiguration> MAPPER;
071
072        static {
073            try {
074                MAPPER = ObjectMapper.factory().get(MyConfiguration.class); // We hold on to the instance of our ObjectMapper
075            } catch (final SerializationException e) {
076                throw new ExceptionInInitializerError(e);
077            }
078        }
079
080        public static MyConfiguration loadFrom(final ConfigurationNode node) throws SerializationException {
081            return MAPPER.load(node);
082        }
083
084        private @Nullable String itemName;
085
086        @Comment("Here is a comment to describe the purpose of this field")
087        private Pattern filter = Pattern.compile("cars?"); // Set defaults by initializing the field
088
089        // As long as custom classes are annotated with @ConfigSerializable, they can be nested as ordinary fields.
090        private List<Section> sections = new ArrayList<>();
091
092        // This won't be written to the file because it's marked as `transient`
093        private transient @MonotonicNonNull String decoratedName;
094
095        public @Nullable String itemName() {
096            return this.itemName;
097        }
098
099        public void itemName(final String itemName) {
100            this.itemName = requireNonNull(itemName, "itemName");
101        }
102
103        public Pattern filter() {
104            return this.filter;
105        }
106
107        public List<Section> sections() {
108            return this.sections;
109        }
110
111        public String decoratedItemName() {
112            if (this.decoratedName == null) {
113                this.decoratedName = "[" + this.itemName + "]";
114            }
115            return this.decoratedName;
116        }
117
118        public <N extends ScopedConfigurationNode<N>> void saveTo(final N node) throws SerializationException {
119            MAPPER.save(this, node);
120        }
121
122    }
123
124    @ConfigSerializable
125    static class Section {
126
127        private String name;
128        private UUID id;
129
130        // the ObjectMapper resolves settings based on fields -- these methods are provided as a convenience
131        public String name() {
132            return this.name;
133        }
134
135        public UUID id() {
136            return this.id;
137        }
138
139    }
140
141}