From 9adc51f8d74577b5c4ae9c1f88341252f2c22939 Mon Sep 17 00:00:00 2001 From: sowgro Date: Thu, 13 Nov 2025 20:05:25 -0500 Subject: export almost working --- .../userinput/menus/ImportExportMenu.java | 58 +++++++++---------- .../controller/userinput/menus/MainMenu.java | 3 +- .../controller/userinput/menus/UserSettings.java | 3 - src/main/java/design/model/DataHandler.java | 11 ---- src/main/java/design/persistence/JSONHandler.java | 28 --------- .../design/persistence/JSONLeagueDatabase.java | 21 ++++--- .../design/persistence/JSONPersonalDatabase.java | 27 ++++----- .../java/design/persistence/LeagueDatabase.java | 3 +- .../java/design/persistence/PersonalDatabase.java | 5 +- src/main/java/design/persistence/XMLHandler.java | 66 ---------------------- .../persistence/importexport/DataHandler.java | 11 ++++ .../persistence/importexport/DataSource.java | 12 ++++ .../persistence/importexport/JSONHandler.java | 30 ++++++++++ .../persistence/importexport/XMLHandler.java | 34 +++++++++++ 14 files changed, 145 insertions(+), 167 deletions(-) delete mode 100644 src/main/java/design/model/DataHandler.java delete mode 100644 src/main/java/design/persistence/JSONHandler.java delete mode 100644 src/main/java/design/persistence/XMLHandler.java create mode 100644 src/main/java/design/persistence/importexport/DataHandler.java create mode 100644 src/main/java/design/persistence/importexport/DataSource.java create mode 100644 src/main/java/design/persistence/importexport/JSONHandler.java create mode 100644 src/main/java/design/persistence/importexport/XMLHandler.java (limited to 'src/main/java/design') diff --git a/src/main/java/design/controller/userinput/menus/ImportExportMenu.java b/src/main/java/design/controller/userinput/menus/ImportExportMenu.java index dbad0e3..dda465f 100644 --- a/src/main/java/design/controller/userinput/menus/ImportExportMenu.java +++ b/src/main/java/design/controller/userinput/menus/ImportExportMenu.java @@ -2,22 +2,18 @@ package design.controller.userinput.menus; import design.controller.userinput.Menu; import design.controller.userinput.MenuOption; -import design.persistence.JSONHandler; -import design.persistence.XMLHandler; +import design.persistence.*; +import design.persistence.importexport.DataHandler; +import design.persistence.importexport.DataSource; +import design.persistence.importexport.JSONHandler; +import design.persistence.importexport.XMLHandler; import java.io.File; import java.io.IOException; import java.util.List; -import java.util.Map; import java.util.Scanner; -import design.model.DataHandler; - public class ImportExportMenu extends Menu { - private static final Map handlers = Map.of( - "xml", new XMLHandler(), - "json", new JSONHandler() - ); @Override public String getTitle() { @@ -31,46 +27,50 @@ public class ImportExportMenu extends Menu { opts.add(new MenuOption("return to main menu", () -> new MainMenu().present())); - opts.add(new MenuOption("import league...", () -> promptForPath(true, false))); - opts.add(new MenuOption("export league...", () -> promptForPath(false, false))); - opts.add(new MenuOption("import personal profile...", () -> promptForPath(true, true))); - opts.add(new MenuOption("export personal profile...", () -> promptForPath(false, true))); + opts.add(new MenuOption("import leagues...", () -> promptForPath(true, false))); + opts.add(new MenuOption("export leagues...", () -> promptForPath(false, false))); + opts.add(new MenuOption("import profiles...", () -> promptForPath(true, true))); + opts.add(new MenuOption("export profiles...", () -> promptForPath(false, true))); return opts; } private void promptForPath(boolean isImporting, boolean isPersonalProfile) { - System.out.println("Enter file path: "); + System.out.print("Enter file path: "); Scanner sc = new Scanner(System.in); String filePath = sc.nextLine(); File file = new File(filePath); - String ext = getExtension(filePath); - DataHandler handler = handlers.get(ext); + DataSource source; + if (isPersonalProfile) { + source = PersonalDatabase.instance(); + } else { + source = LeagueDatabase.instance(); + } - if (handler == null) { - System.out.println("Unsupported file type: " + ext); - return; + DataHandler handler; + String ext = getExtension(filePath); + switch (ext) { + case "json" -> handler = new JSONHandler(source); + case "xml" -> handler = new XMLHandler(source); + default -> { + System.out.println("Unsupported file type: " + ext); + return; + } } try { if (isImporting) { - if (isPersonalProfile) - handler.importPersonalData(file); - else - handler.importLeagueData(file); + handler.importData(file); } else { - if (isPersonalProfile) - handler.exportPersonalData(file); - else - handler.exportLeagueData(file); + handler.exportData(file); } } catch (IOException e) { - System.err.println("I/O error: " + e.getMessage()); + throw new RuntimeException(e); } - new ImportExportMenu().present(); + this.present(); } private static String getExtension(String fileName) { diff --git a/src/main/java/design/controller/userinput/menus/MainMenu.java b/src/main/java/design/controller/userinput/menus/MainMenu.java index 7522ceb..9d5204f 100644 --- a/src/main/java/design/controller/userinput/menus/MainMenu.java +++ b/src/main/java/design/controller/userinput/menus/MainMenu.java @@ -19,7 +19,8 @@ public class MainMenu extends Menu { new MenuOption("manage courses...", () -> new ManageCourses().present()), new MenuOption("manage clubs...", () -> new ManageClubs().present()), new MenuOption("statistics...", () -> new StatisticsMenu().present()), - new MenuOption("log round...", () -> new HolePlayMenu().present()) + new MenuOption("log round...", () -> new HolePlayMenu().present()), + new MenuOption("manage data...", () -> new ImportExportMenu().present()) ); } } diff --git a/src/main/java/design/controller/userinput/menus/UserSettings.java b/src/main/java/design/controller/userinput/menus/UserSettings.java index 865b00d..47b0a5b 100644 --- a/src/main/java/design/controller/userinput/menus/UserSettings.java +++ b/src/main/java/design/controller/userinput/menus/UserSettings.java @@ -60,9 +60,6 @@ public class UserSettings extends Menu { this.present(); })); - opts.add(new MenuOption("manage data...", () -> new ImportExportMenu().present())); - - return opts; } } diff --git a/src/main/java/design/model/DataHandler.java b/src/main/java/design/model/DataHandler.java deleted file mode 100644 index e7dda33..0000000 --- a/src/main/java/design/model/DataHandler.java +++ /dev/null @@ -1,11 +0,0 @@ -package design.model; - -import java.io.File; -import java.io.IOException; - -public interface DataHandler { - void importPersonalData(File file) throws IOException; - void exportPersonalData(File file) throws IOException; - void importLeagueData(File file) throws IOException; - void exportLeagueData(File file) throws IOException; -} \ No newline at end of file diff --git a/src/main/java/design/persistence/JSONHandler.java b/src/main/java/design/persistence/JSONHandler.java deleted file mode 100644 index 77ec987..0000000 --- a/src/main/java/design/persistence/JSONHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -package design.persistence; -import java.io.File; -import java.io.IOException; -import design.model.DataHandler; - -public class JSONHandler implements DataHandler -{ - - public void exportPersonalData(File file) throws IOException { - JSONPersonalDatabase.instance().exportData(file); - } - - public void importPersonalData(File file) throws IOException { - JSONPersonalDatabase.instance().importData(file); - } - - public void exportLeagueData(File file) throws IOException - { - JSONLeagueDatabase.instance().importData(file); - } - - public void importLeagueData(File file) throws IOException - { - JSONLeagueDatabase.instance().exportData(file); - } -} - - diff --git a/src/main/java/design/persistence/JSONLeagueDatabase.java b/src/main/java/design/persistence/JSONLeagueDatabase.java index edc649b..795c582 100644 --- a/src/main/java/design/persistence/JSONLeagueDatabase.java +++ b/src/main/java/design/persistence/JSONLeagueDatabase.java @@ -13,8 +13,6 @@ import design.model.League; import java.io.File; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -100,18 +98,19 @@ public class JSONLeagueDatabase implements LeagueDatabase { save(); } - public File exportData(File newFile) throws IOException{ - Files.copy(file.toPath(), newFile.toPath(), StandardCopyOption.REPLACE_EXISTING); - return newFile; - } - - public void importData(File newFile) throws IOException { - League[] newLeagues = mapper.readValue(newFile, League[].class); + @Override + public void importData(JsonNode tree) throws IOException { + League[] data = mapper.treeToValue(tree, League[].class); cache.clear(); - for (League l: newLeagues) { - cache.put(l.getId(), l); + for (League league : data) { + cache.put(league.getId(), league); } save(); } + @Override + public JsonNode exportData() { + Object[] data = cache.values().toArray(); + return mapper.valueToTree(data); + } } diff --git a/src/main/java/design/persistence/JSONPersonalDatabase.java b/src/main/java/design/persistence/JSONPersonalDatabase.java index 3fc5cab..3e70629 100644 --- a/src/main/java/design/persistence/JSONPersonalDatabase.java +++ b/src/main/java/design/persistence/JSONPersonalDatabase.java @@ -13,8 +13,6 @@ import design.model.League; import java.io.File; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; import java.util.HashMap; import java.util.Map; @@ -38,9 +36,6 @@ public class JSONPersonalDatabase implements PersonalDatabase { this.cache = new HashMap<>(); this.mapper = new ObjectMapper(); - // TODO: Once the saved JSON matches the model, consider removing. - // TEMP: tolerate unknown props while the model stabilizes - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); SimpleModule module = new SimpleModule(); module.addDeserializer(Course.class, new Serializers.CourseIdDeserializer()); @@ -48,6 +43,7 @@ public class JSONPersonalDatabase implements PersonalDatabase { module.addSerializer(League.class, new Serializers.LeagueIDSerializer()); module.addDeserializer(League.class, new Serializers.LeagueIDDeserializer()); mapper.registerModule(module); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); mapper.registerModule(new ParameterNamesModule(JsonCreator.Mode.PROPERTIES)); mapper.registerModule(new JavaTimeModule()); @@ -101,18 +97,19 @@ public class JSONPersonalDatabase implements PersonalDatabase { save(); } - - public File exportData(File newFile) throws IOException{ - Files.copy(file.toPath(), newFile.toPath(), StandardCopyOption.REPLACE_EXISTING); - return newFile; - } - - public void importData(File newFile) throws IOException { - Golfer[] newGolfers = mapper.readValue(newFile, Golfer[].class); + @Override + public void importData(JsonNode tree) throws IOException { + Golfer[] data = mapper.treeToValue(tree, Golfer[].class); cache.clear(); - for (Golfer g : newGolfers) { - cache.put(g.getUsername(), g); + for (Golfer golfer : data) { + cache.put(golfer.getUsername(), golfer); } save(); } + + @Override + public JsonNode exportData() { + Object[] data = cache.values().toArray(); + return mapper.valueToTree(data); + } } diff --git a/src/main/java/design/persistence/LeagueDatabase.java b/src/main/java/design/persistence/LeagueDatabase.java index 953624d..9f835ff 100644 --- a/src/main/java/design/persistence/LeagueDatabase.java +++ b/src/main/java/design/persistence/LeagueDatabase.java @@ -1,10 +1,11 @@ package design.persistence; import design.model.League; +import design.persistence.importexport.DataSource; import java.io.IOException; -public interface LeagueDatabase { +public interface LeagueDatabase extends DataSource { static LeagueDatabase instance() { return JSONLeagueDatabase.instance(); } diff --git a/src/main/java/design/persistence/PersonalDatabase.java b/src/main/java/design/persistence/PersonalDatabase.java index 63f9182..77e43cc 100644 --- a/src/main/java/design/persistence/PersonalDatabase.java +++ b/src/main/java/design/persistence/PersonalDatabase.java @@ -1,10 +1,11 @@ package design.persistence; import design.model.Golfer; +import design.persistence.importexport.DataSource; + import java.io.IOException; -import java.io.File; -public interface PersonalDatabase { +public interface PersonalDatabase extends DataSource { static PersonalDatabase instance() { return JSONPersonalDatabase.instance(); diff --git a/src/main/java/design/persistence/XMLHandler.java b/src/main/java/design/persistence/XMLHandler.java deleted file mode 100644 index 706dabd..0000000 --- a/src/main/java/design/persistence/XMLHandler.java +++ /dev/null @@ -1,66 +0,0 @@ -package design.persistence; -import java.io.File; -import java.io.IOException; -import design.model.DataHandler; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; - -import design.model.Golfer; -import com.fasterxml.jackson.dataformat.xml.XmlMapper; - - - -public class XMLHandler implements DataHandler -{ - private final ObjectMapper jsonMapper = new ObjectMapper(); - private final XmlMapper xmlMapper = new XmlMapper(); - - public void exportPersonalData(File file) throws IOException { - // get our json data just from the JSON database - File jsonData = JSONPersonalDatabase.instance().exportData(file); - - // read the the data from the JSON, as a JsonNode. - JsonNode golfersNode = jsonMapper.readTree(jsonData); - - // XML requires a parent node, we can't just throw the golfersnode into the xml or else it will only produce the first element - ObjectNode root = xmlMapper.createObjectNode(); - root.set("golfer", golfersNode); - - //write to the xml file. - xmlMapper.writerWithDefaultPrettyPrinter().writeValue(file, root); - } - - public void importPersonalData(File file) throws IOException { - - // read our root, the object node - JsonNode root = xmlMapper.readTree(file); - - // debug print line - System.out.println(root.toPrettyString()); - - // !!! here is where it's failing...our root is not serializable to an array of golfers. !!! - Golfer[] golfers = xmlMapper.treeToValue(root, Golfer[].class); - - // from here out should be good - File tempJson = File.createTempFile("imported", ".json"); - jsonMapper.writerWithDefaultPrettyPrinter().writeValue(tempJson, golfers); - JSONPersonalDatabase.instance().importData(tempJson); - tempJson.delete(); - } - - - - public void exportLeagueData(File file) throws IOException - { - // TO DO: exporting league data - } - - public void importLeagueData(File file) throws IOException - { - // TO DO: importing league data - } -} - - diff --git a/src/main/java/design/persistence/importexport/DataHandler.java b/src/main/java/design/persistence/importexport/DataHandler.java new file mode 100644 index 0000000..59df9be --- /dev/null +++ b/src/main/java/design/persistence/importexport/DataHandler.java @@ -0,0 +1,11 @@ +package design.persistence.importexport; + +import java.io.File; +import java.io.IOException; + +public interface DataHandler { + + void importData(File file) throws IOException; + + void exportData(File file) throws IOException; +} diff --git a/src/main/java/design/persistence/importexport/DataSource.java b/src/main/java/design/persistence/importexport/DataSource.java new file mode 100644 index 0000000..5290e33 --- /dev/null +++ b/src/main/java/design/persistence/importexport/DataSource.java @@ -0,0 +1,12 @@ +package design.persistence.importexport; + +import com.fasterxml.jackson.databind.JsonNode; + +import java.io.IOException; + +public interface DataSource { + + void importData(JsonNode tree) throws IOException; + + JsonNode exportData() throws IOException; +} \ No newline at end of file diff --git a/src/main/java/design/persistence/importexport/JSONHandler.java b/src/main/java/design/persistence/importexport/JSONHandler.java new file mode 100644 index 0000000..239eb6b --- /dev/null +++ b/src/main/java/design/persistence/importexport/JSONHandler.java @@ -0,0 +1,30 @@ +package design.persistence.importexport; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.json.JsonMapper; + +import java.io.File; +import java.io.IOException; + +public class JSONHandler implements DataHandler { + + private final DataSource dataSource; + private final JsonMapper jsonMapper = new JsonMapper(); + + public JSONHandler(DataSource dataSource) { + this.dataSource = dataSource; + } + + @Override + public void importData(File file) throws IOException { + JsonNode tree = jsonMapper.readTree(file); + dataSource.importData(tree); + } + + @Override + public void exportData(File file) throws IOException{ + JsonNode tree = dataSource.exportData(); + jsonMapper.writerWithDefaultPrettyPrinter().writeValue(file, tree); + } +} + + diff --git a/src/main/java/design/persistence/importexport/XMLHandler.java b/src/main/java/design/persistence/importexport/XMLHandler.java new file mode 100644 index 0000000..1a16b90 --- /dev/null +++ b/src/main/java/design/persistence/importexport/XMLHandler.java @@ -0,0 +1,34 @@ +package design.persistence.importexport; +import java.io.File; +import java.io.IOException; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; + +public class XMLHandler implements DataHandler { + + private final DataSource dataSource; + private final XmlMapper xmlMapper = new XmlMapper(); + + public XMLHandler(DataSource dataSource) { + this.dataSource = dataSource; + } + + @Override + public void importData(File file) throws IOException { + JsonNode tree = xmlMapper.readTree(file); + JsonNode unwrapped = tree.get("items"); + dataSource.importData(unwrapped); + } + + @Override + public void exportData(File file) throws IOException { + JsonNode tree = dataSource.exportData(); + ObjectNode wrapper = xmlMapper.createObjectNode(); + wrapper.set("items", tree); + xmlMapper.writerWithDefaultPrettyPrinter().withRootName("export").writeValue(file, wrapper); + } +} + + -- cgit v1.2.3