From a8def7d9a5348fa1b662b31238ff5ce642caee45 Mon Sep 17 00:00:00 2001 From: Jun An Date: Tue, 7 Aug 2018 17:25:39 +0800 Subject: [PATCH 1/2] Storage: add AddressBookEncoder and AddressBookDecoder classes Storage uses the JAXB module for storing and retrieving of the address book data in a file. However, we are trying to ensure Java 9 compatibility in #381, but the JAXB module is deprecated from Java 9 onwards. As use of deprecated modules is considered bad practice, we should replace our storage needs with another library before moving on to ensure Java 9 compatiblity. As suggested here[1], let's reuse the storage code from addressbook-level1. To do this, let's create new classes, AddressBookEncoder and AddressBookDecoder, which contains the ported storage code from addressbook-level1, and update StorageFile to use them. [1]: https://github.com/se-edu/addressbook-level2/pull/382#issuecomment-409441789 --- .gitignore | 2 +- .../storage/AddressBookDecoder.java | 90 +++++++++++++++++++ .../storage/AddressBookEncoder.java | 45 ++++++++++ .../addressbook/storage/StorageFile.java | 74 ++++----------- test/data/StorageFileTest/InvalidData.txt | 1 + test/data/StorageFileTest/InvalidData.xml | 6 -- test/data/StorageFileTest/ValidData.txt | 2 + test/data/StorageFileTest/ValidData.xml | 17 ---- test/expected.txt | 2 +- .../addressbook/storage/StorageFileTest.java | 12 +-- 10 files changed, 162 insertions(+), 89 deletions(-) create mode 100644 src/seedu/addressbook/storage/AddressBookDecoder.java create mode 100644 src/seedu/addressbook/storage/AddressBookEncoder.java create mode 100644 test/data/StorageFileTest/InvalidData.txt delete mode 100644 test/data/StorageFileTest/InvalidData.xml create mode 100644 test/data/StorageFileTest/ValidData.txt delete mode 100644 test/data/StorageFileTest/ValidData.xml diff --git a/.gitignore b/.gitignore index 9c362a58e..97c90afa9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # Default storage file for addressbook : don't need to cleanup when running from IDE -addressbook.xml +addressbook.txt # Compiled classfiles bin/ diff --git a/src/seedu/addressbook/storage/AddressBookDecoder.java b/src/seedu/addressbook/storage/AddressBookDecoder.java new file mode 100644 index 000000000..b277f18a3 --- /dev/null +++ b/src/seedu/addressbook/storage/AddressBookDecoder.java @@ -0,0 +1,90 @@ +package seedu.addressbook.storage; + +import static seedu.addressbook.parser.Parser.PERSON_DATA_ARGS_FORMAT; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; + +import seedu.addressbook.data.AddressBook; +import seedu.addressbook.data.exception.IllegalValueException; +import seedu.addressbook.data.person.Address; +import seedu.addressbook.data.person.Email; +import seedu.addressbook.data.person.Name; +import seedu.addressbook.data.person.Person; +import seedu.addressbook.data.person.Phone; +import seedu.addressbook.data.person.UniquePersonList; +import seedu.addressbook.data.tag.Tag; +import seedu.addressbook.storage.StorageFile.StorageOperationException; + +/** + * Decodes the storage data file into an {@code AddressBook} object. + */ +public class AddressBookDecoder { + + /** + * Decodes {@code encodedAddressBook} into an {@code AddressBook} containing the decoded persons. + * + * @throws IllegalValueException if any of the fields in any encoded person string is invalid. + * @throws StorageOperationException if the {@code encodedAddressBook} is in an invalid format. + */ + public static AddressBook decodeAddressBook(List encodedAddressBook) + throws IllegalValueException, StorageOperationException { + final List decodedPersons = new ArrayList<>(); + for (String encodedPerson : encodedAddressBook) { + decodedPersons.add(decodePersonFromString(encodedPerson)); + } + return new AddressBook(new UniquePersonList(decodedPersons)); + } + + /** + * Decodes {@code encodedPerson} into a {@code Person}. + * + * @throws IllegalValueException if any field in the {@code encodedPerson} is invalid. + * @throws StorageOperationException if {@code encodedPerson} is in an invalid format. + */ + private static Person decodePersonFromString(String encodedPerson) + throws IllegalValueException, StorageOperationException { + final Matcher matcher = PERSON_DATA_ARGS_FORMAT.matcher(encodedPerson); + if (!matcher.matches()) { + throw new StorageOperationException("Encoded person in invalid format. Unable to decode."); + } + + return new Person( + new Name(matcher.group("name")), + new Phone(matcher.group("phone"), isPrivatePrefixPresent(matcher.group("isPhonePrivate"))), + new Email(matcher.group("email"), isPrivatePrefixPresent(matcher.group("isEmailPrivate"))), + new Address(matcher.group("address"), isPrivatePrefixPresent(matcher.group("isAddressPrivate"))), + getTagsFromEncodedPerson(matcher.group("tagArguments")) + ); + } + + /** + * Returns true if {@code matchedPrefix} is equal to the private prefix for contact details. + */ + private static boolean isPrivatePrefixPresent(String matchedPrefix) { + return "p".equals(matchedPrefix); + } + + /** + * Extracts the {@code Tag}s from the {@code tagArguments} string. + * Merges duplicate tag strings. + */ + private static Set getTagsFromEncodedPerson(String tagArguments) throws IllegalValueException { + if (tagArguments.isEmpty()) { + return Collections.emptySet(); + } + + // replace first delimiter prefix, then split + final String[] tagStrings = tagArguments.replaceFirst(" t/", "").split(" t/"); + final Set tagSet = new HashSet<>(); + for (String tagName : tagStrings) { + tagSet.add(new Tag(tagName)); + } + + return tagSet; + } +} diff --git a/src/seedu/addressbook/storage/AddressBookEncoder.java b/src/seedu/addressbook/storage/AddressBookEncoder.java new file mode 100644 index 000000000..8cb206a8a --- /dev/null +++ b/src/seedu/addressbook/storage/AddressBookEncoder.java @@ -0,0 +1,45 @@ +package seedu.addressbook.storage; + +import java.util.ArrayList; +import java.util.List; + +import seedu.addressbook.data.AddressBook; +import seedu.addressbook.data.person.Person; + +/** + * Encodes the {@code AddressBook} object into a data file for storage. + */ +public class AddressBookEncoder { + + /** + * Encodes all the {@code Person} in the {@code toSave} into a list of decodable and readable string presentation + * for storage. + */ + public static List encodeAddressBook(AddressBook toSave) { + final List encodedPersons = new ArrayList<>(); + toSave.getAllPersons().forEach(person -> encodedPersons.add(encodePersonToString(person))); + return encodedPersons; + } + + /** + * Encodes the {@code person} into a decodable and readable string representation. + */ + private static String encodePersonToString(Person person) { + final StringBuilder encodedPersonBuilder = new StringBuilder(); + + encodedPersonBuilder.append(person.getName()); + + encodedPersonBuilder.append(person.getPhone().isPrivate() ? " p" : " "); + encodedPersonBuilder.append("p/").append(person.getPhone().value); + + encodedPersonBuilder.append(person.getEmail().isPrivate() ? " p" : " "); + encodedPersonBuilder.append("e/").append(person.getEmail().value); + + encodedPersonBuilder.append(person.getAddress().isPrivate() ? " p" : " "); + encodedPersonBuilder.append("a/").append(person.getAddress().value); + + person.getTags().forEach(tag -> encodedPersonBuilder.append(" t/").append(tag.tagName)); + + return encodedPersonBuilder.toString(); + } +} diff --git a/src/seedu/addressbook/storage/StorageFile.java b/src/seedu/addressbook/storage/StorageFile.java index 459632e67..41147edf5 100644 --- a/src/seedu/addressbook/storage/StorageFile.java +++ b/src/seedu/addressbook/storage/StorageFile.java @@ -1,25 +1,14 @@ package seedu.addressbook.storage; -import seedu.addressbook.data.AddressBook; -import seedu.addressbook.data.exception.IllegalValueException; -import seedu.addressbook.storage.jaxb.AdaptedAddressBook; - -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; -import javax.xml.bind.Unmarshaller; - -import java.io.BufferedReader; -import java.io.BufferedWriter; import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; import java.io.IOException; -import java.io.Reader; -import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.List; + +import seedu.addressbook.data.AddressBook; +import seedu.addressbook.data.exception.IllegalValueException; /** * Represents the file used to store address book data. @@ -27,7 +16,7 @@ public class StorageFile { /** Default file path used if the user doesn't provide the file name. */ - public static final String DEFAULT_STORAGE_FILEPATH = "addressbook.xml"; + public static final String DEFAULT_STORAGE_FILEPATH = "addressbook.txt"; /* Note: Note the use of nested classes below. * More info https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html @@ -52,8 +41,6 @@ public StorageOperationException(String message) { } } - private final JAXBContext jaxbContext; - public final Path path; /** @@ -67,56 +54,38 @@ public StorageFile() throws InvalidStorageFilePathException { * @throws InvalidStorageFilePathException if the given file path is invalid */ public StorageFile(String filePath) throws InvalidStorageFilePathException { - try { - jaxbContext = JAXBContext.newInstance(AdaptedAddressBook.class); - } catch (JAXBException jaxbe) { - throw new RuntimeException("jaxb initialisation error"); - } - path = Paths.get(filePath); if (!isValidPath(path)) { - throw new InvalidStorageFilePathException("Storage file should end with '.xml'"); + throw new InvalidStorageFilePathException("Storage file should end with '.txt'"); } } /** * Returns true if the given path is acceptable as a storage file. - * The file path is considered acceptable if it ends with '.xml' + * The file path is considered acceptable if it ends with '.txt' */ private static boolean isValidPath(Path filePath) { - return filePath.toString().endsWith(".xml"); + return filePath.toString().endsWith(".txt"); } /** - * Saves all data to this storage file. + * Saves the {@code addressBook} data to the storage file. * * @throws StorageOperationException if there were errors converting and/or storing data to file. */ public void save(AddressBook addressBook) throws StorageOperationException { - - /* Note: Note the 'try with resource' statement below. - * More info: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html - */ - try (final Writer fileWriter = - new BufferedWriter(new FileWriter(path.toFile()))) { - - final AdaptedAddressBook toSave = new AdaptedAddressBook(addressBook); - final Marshaller marshaller = jaxbContext.createMarshaller(); - marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); - marshaller.marshal(toSave, fileWriter); - + try { + List encodedAddressBook = AddressBookEncoder.encodeAddressBook(addressBook); + Files.write(path, encodedAddressBook); } catch (IOException ioe) { throw new StorageOperationException("Error writing to file: " + path); - } catch (JAXBException jaxbe) { - throw new StorageOperationException("Error converting address book into storage format"); } } /** - * Loads data from this storage file. + * Loads the {@code AddressBook} data from this storage file, and then returns it. + * Returns an empty {@code AddressBook} if the file does not exist, or is not a regular file. * - * @return an {@link AddressBook} containing the data in the file, or an empty {@link AddressBook} if it - * does not exist. * @throws StorageOperationException if there were errors reading and/or converting data from file. */ public AddressBook load() throws StorageOperationException { @@ -125,24 +94,13 @@ public AddressBook load() throws StorageOperationException { return new AddressBook(); } - try (final Reader fileReader = - new BufferedReader(new FileReader(path.toFile()))) { - - final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); - final AdaptedAddressBook loaded = (AdaptedAddressBook) unmarshaller.unmarshal(fileReader); - // manual check for missing elements - if (loaded.isAnyRequiredFieldMissing()) { - throw new StorageOperationException("File data missing some elements"); - } - return loaded.toModelType(); - + try { + return AddressBookDecoder.decodeAddressBook(Files.readAllLines(path)); } catch (FileNotFoundException fnfe) { throw new AssertionError("A non-existent file scenario is already handled earlier."); // other errors } catch (IOException ioe) { throw new StorageOperationException("Error writing to file: " + path); - } catch (JAXBException jaxbe) { - throw new StorageOperationException("Error parsing file data format"); } catch (IllegalValueException ive) { throw new StorageOperationException("File contains illegal data values; data type constraints not met"); } diff --git a/test/data/StorageFileTest/InvalidData.txt b/test/data/StorageFileTest/InvalidData.txt new file mode 100644 index 000000000..6320cd248 --- /dev/null +++ b/test/data/StorageFileTest/InvalidData.txt @@ -0,0 +1 @@ +data \ No newline at end of file diff --git a/test/data/StorageFileTest/InvalidData.xml b/test/data/StorageFileTest/InvalidData.xml deleted file mode 100644 index 91e8971a4..000000000 --- a/test/data/StorageFileTest/InvalidData.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - data - - diff --git a/test/data/StorageFileTest/ValidData.txt b/test/data/StorageFileTest/ValidData.txt new file mode 100644 index 000000000..224fb9acd --- /dev/null +++ b/test/data/StorageFileTest/ValidData.txt @@ -0,0 +1,2 @@ +John Doe p/98765432 e/johnd@gmail.com a/John street, block 123, #01-01 +Betsy Crowe pp/1234567 e/betsycrowe@gmail.com pa/Newgate Prison t/friend t/criminal diff --git a/test/data/StorageFileTest/ValidData.xml b/test/data/StorageFileTest/ValidData.xml deleted file mode 100644 index fc6b00df6..000000000 --- a/test/data/StorageFileTest/ValidData.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - John Doe - 98765432 - johnd@gmail.com -
John street, block 123, #01-01
-
- - Betsy Crowe - 1234567 - betsycrowe@gmail.com -
Newgate Prison
- friend - criminal -
-
diff --git a/test/expected.txt b/test/expected.txt index 49993eaa1..56fe5fcac 100644 --- a/test/expected.txt +++ b/test/expected.txt @@ -3,7 +3,7 @@ || Welcome to your Address Book! || AddressBook Level 2 - Version 1.0 || Launch command format: java seedu.addressbook.Main [STORAGE_FILE_PATH] -|| Using storage file : addressbook.xml +|| Using storage file : addressbook.txt || =================================================== || Enter command: || [Command entered: sfdfd] || add: Adds a person to the address book. Contact details can be marked private by prepending 'p' to the prefix. diff --git a/test/java/seedu/addressbook/storage/StorageFileTest.java b/test/java/seedu/addressbook/storage/StorageFileTest.java index 73af385d6..f2c907296 100644 --- a/test/java/seedu/addressbook/storage/StorageFileTest.java +++ b/test/java/seedu/addressbook/storage/StorageFileTest.java @@ -26,7 +26,7 @@ public class StorageFileTest { private static final String TEST_DATA_FOLDER = "test/data/StorageFileTest"; - private static final String NON_EXISTANT_FILE_NAME = "ThisFileDoesNotExist.xml"; + private static final String NON_EXISTANT_FILE_NAME = "ThisFileDoesNotExist.txt"; @Rule public ExpectedException thrown = ExpectedException.none(); @@ -48,15 +48,15 @@ public void constructor_noTxtExtension_exceptionThrown() throws Exception { @Test public void load_invalidFormat_exceptionThrown() throws Exception { - // The file contains valid xml data, but does not match the AddressBook class - StorageFile storage = getStorage("InvalidData.xml"); + // The file contains valid txt data, but does not match the Person format + StorageFile storage = getStorage("InvalidData.txt"); thrown.expect(StorageOperationException.class); storage.load(); } @Test public void load_validFormat() throws Exception { - AddressBook actualAB = getStorage("ValidData.xml").load(); + AddressBook actualAB = getStorage("ValidData.txt").load(); AddressBook expectedAB = getTestAddressBook(); // ensure loaded AddressBook is properly constructed with test data @@ -88,7 +88,7 @@ public void save_validAddressBook() throws Exception { StorageFile storage = getTempStorage(); storage.save(ab); - assertStorageFilesEqual(storage, getStorage("ValidData.xml")); + assertStorageFilesEqual(storage, getStorage("ValidData.txt")); } // getPath() method in StorageFile class is trivial so it is not tested @@ -105,7 +105,7 @@ private StorageFile getStorage(String fileName) throws Exception { } private StorageFile getTempStorage() throws Exception { - return new StorageFile(testFolder.getRoot().getPath() + "/" + "temp.xml"); + return new StorageFile(testFolder.getRoot().getPath() + "/" + "temp.txt"); } private AddressBook getTestAddressBook() throws Exception { From 9ee7769307cecbd5aa92bad693ae064781eb857c Mon Sep 17 00:00:00 2001 From: Jun An Date: Wed, 8 Aug 2018 23:47:07 +0800 Subject: [PATCH 2/2] jaxb: remove unused classes jaxb contains the JAXB-friendly adapted classes for conversion from .xml storage data file to the specified Java object. As we have replaced our storage needs with the ported addressbook-level1 code, the JAXB module is no longer used. As such the JAXB-friendly adapted adapted classes in jaxb are no longer needed. Let's remove these unused classes in jaxb. --- .../storage/jaxb/AdaptedAddressBook.java | 70 ----------- .../storage/jaxb/AdaptedPerson.java | 113 ------------------ .../addressbook/storage/jaxb/AdaptedTag.java | 51 -------- 3 files changed, 234 deletions(-) delete mode 100644 src/seedu/addressbook/storage/jaxb/AdaptedAddressBook.java delete mode 100644 src/seedu/addressbook/storage/jaxb/AdaptedPerson.java delete mode 100644 src/seedu/addressbook/storage/jaxb/AdaptedTag.java diff --git a/src/seedu/addressbook/storage/jaxb/AdaptedAddressBook.java b/src/seedu/addressbook/storage/jaxb/AdaptedAddressBook.java deleted file mode 100644 index 8fcab82fb..000000000 --- a/src/seedu/addressbook/storage/jaxb/AdaptedAddressBook.java +++ /dev/null @@ -1,70 +0,0 @@ -package seedu.addressbook.storage.jaxb; - -import seedu.addressbook.data.AddressBook; -import seedu.addressbook.data.exception.IllegalValueException; -import seedu.addressbook.data.person.Person; -import seedu.addressbook.data.person.ReadOnlyPerson; -import seedu.addressbook.data.person.UniquePersonList; - -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import java.util.ArrayList; -import java.util.List; - -/** - * JAXB-friendly adapted address book data holder class. - */ -@XmlRootElement(name = "AddressBook") -public class AdaptedAddressBook { - - @XmlElement - private List persons = new ArrayList<>(); - - /** - * No-arg constructor for JAXB use. - */ - public AdaptedAddressBook() {} - - /** - * Converts a given AddressBook into this class for JAXB use. - * - * @param source future changes to this will not affect the created AdaptedAddressBook - */ - public AdaptedAddressBook(AddressBook source) { - persons = new ArrayList<>(); - for (ReadOnlyPerson person : source.getAllPersons()) { - persons.add(new AdaptedPerson(person)); - } - } - - - /** - * Returns true if any required field is missing. - * - * JAXB does not enforce (required = true) without a given XML schema. - * Since we do most of our validation using the data class constructors, the only extra logic we need - * is to ensure that every xml element in the document is present. JAXB sets missing elements as null, - * so we check for that. - */ - public boolean isAnyRequiredFieldMissing() { - for (AdaptedPerson person : persons) { - if (person.isAnyRequiredFieldMissing()) { - return true; - } - } - return false; - } - - - /** - * Converts this jaxb-friendly {@code AdaptedAddressBook} object into the corresponding(@code AddressBook} object. - * @throws IllegalValueException if there were any data constraints violated in the adapted person - */ - public AddressBook toModelType() throws IllegalValueException { - final List personList = new ArrayList<>(); - for (AdaptedPerson person : persons) { - personList.add(person.toModelType()); - } - return new AddressBook(new UniquePersonList(personList)); - } -} diff --git a/src/seedu/addressbook/storage/jaxb/AdaptedPerson.java b/src/seedu/addressbook/storage/jaxb/AdaptedPerson.java deleted file mode 100644 index 4ade0ccbf..000000000 --- a/src/seedu/addressbook/storage/jaxb/AdaptedPerson.java +++ /dev/null @@ -1,113 +0,0 @@ -package seedu.addressbook.storage.jaxb; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlValue; - -import seedu.addressbook.common.Utils; -import seedu.addressbook.data.exception.IllegalValueException; -import seedu.addressbook.data.person.Address; -import seedu.addressbook.data.person.Email; -import seedu.addressbook.data.person.Name; -import seedu.addressbook.data.person.Person; -import seedu.addressbook.data.person.Phone; -import seedu.addressbook.data.person.ReadOnlyPerson; -import seedu.addressbook.data.tag.Tag; - -/** - * JAXB-friendly adapted person data holder class. - */ -public class AdaptedPerson { - - private static class AdaptedContactDetail { - @XmlValue - public String value; - @XmlAttribute(required = true) - public boolean isPrivate; - } - - @XmlElement(required = true) - private String name; - @XmlElement(required = true) - private AdaptedContactDetail phone; - @XmlElement(required = true) - private AdaptedContactDetail email; - @XmlElement(required = true) - private AdaptedContactDetail address; - - @XmlElement - private List tagged = new ArrayList<>(); - - /** - * No-arg constructor for JAXB use. - */ - public AdaptedPerson() {} - - - /** - * Converts a given Person into this class for JAXB use. - * - * @param source future changes to this will not affect the created AdaptedPerson - */ - public AdaptedPerson(ReadOnlyPerson source) { - name = source.getName().fullName; - - phone = new AdaptedContactDetail(); - phone.isPrivate = source.getPhone().isPrivate(); - phone.value = source.getPhone().value; - - email = new AdaptedContactDetail(); - email.isPrivate = source.getEmail().isPrivate(); - email.value = source.getEmail().value; - - address = new AdaptedContactDetail(); - address.isPrivate = source.getAddress().isPrivate(); - address.value = source.getAddress().value; - - tagged = new ArrayList<>(); - for (Tag tag : source.getTags()) { - tagged.add(new AdaptedTag(tag)); - } - } - - /** - * Returns true if any required field is missing. - * - * JAXB does not enforce (required = true) without a given XML schema. - * Since we do most of our validation using the data class constructors, the only extra logic we need - * is to ensure that every xml element in the document is present. JAXB sets missing elements as null, - * so we check for that. - */ - public boolean isAnyRequiredFieldMissing() { - for (AdaptedTag tag : tagged) { - if (tag.isAnyRequiredFieldMissing()) { - return true; - } - } - // second call only happens if phone/email/address are all not null - return Utils.isAnyNull(name, phone, email, address) - || Utils.isAnyNull(phone.value, email.value, address.value); - } - - /** - * Converts this jaxb-friendly adapted person object into the Person object. - * - * @throws IllegalValueException if there were any data constraints violated in the adapted person - */ - public Person toModelType() throws IllegalValueException { - final Set personTags = new HashSet<>(); - for (AdaptedTag tag : tagged) { - personTags.add(tag.toModelType()); - } - final Name name = new Name(this.name); - final Phone phone = new Phone(this.phone.value, this.phone.isPrivate); - final Email email = new Email(this.email.value, this.email.isPrivate); - final Address address = new Address(this.address.value, this.address.isPrivate); - return new Person(name, phone, email, address, personTags); - } -} diff --git a/src/seedu/addressbook/storage/jaxb/AdaptedTag.java b/src/seedu/addressbook/storage/jaxb/AdaptedTag.java deleted file mode 100644 index cd5286a36..000000000 --- a/src/seedu/addressbook/storage/jaxb/AdaptedTag.java +++ /dev/null @@ -1,51 +0,0 @@ -package seedu.addressbook.storage.jaxb; - -import seedu.addressbook.common.Utils; -import seedu.addressbook.data.exception.IllegalValueException; -import seedu.addressbook.data.tag.Tag; - -import javax.xml.bind.annotation.XmlValue; - -/** - * JAXB-friendly adapted tag data holder class. - */ -public class AdaptedTag { - - @XmlValue - public String tagName; - - /** - * No-arg constructor for JAXB use. - */ - public AdaptedTag() {} - - /** - * Converts a given Tag into this class for JAXB use. - * - * @param source future changes to this will not affect the created AdaptedTag - */ - public AdaptedTag(Tag source) { - tagName = source.tagName; - } - - /** - * Returns true if any required field is missing. - * - * JAXB does not enforce (required = true) without a given XML schema. - * Since we do most of our validation using the data class constructors, the only extra logic we need - * is to ensure that every xml element in the document is present. JAXB sets missing elements as null, - * so we check for that. - */ - public boolean isAnyRequiredFieldMissing() { - return Utils.isAnyNull(tagName); - } - - /** - * Converts this jaxb-friendly adapted tag object into the Tag object. - * - * @throws IllegalValueException if there were any data constraints violated in the adapted person - */ - public Tag toModelType() throws IllegalValueException { - return new Tag(tagName); - } -}