gt:             HashMap<Column, Object> dataSet = data.toDatabaseEntryList();
context: // Copyright (c) 2012 - 2015, CanaryMod Team
  // Under the management of PlayBlack and Visual Illusions Entertainment
  // All rights reserved.
  // 
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are met:
  //     * Redistributions of source code must retain the above copyright
  //       notice, this list of conditions and the following disclaimer.
  //     * Redistributions in binary form must reproduce the above copyright
  //       notice, this list of conditions and the following disclaimer in the
  //       documentation and/or other materials provided with the distribution.
  //     * Neither the name of the CanaryMod Team nor the
  //       names of its contributors may be used to endorse or promote products
  //       derived from this software without specific prior written permission.
  // 
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  // DISCLAIMED. IN NO EVENT SHALL CANARYMOD TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  // 
  // Any source code from the Minecraft Server is not owned by CanaryMod Team, PlayBlack,
  // Visual Illusions Entertainment, or its contributors and is not covered by above license.
  // Usage of source code from the Minecraft Server is subject to the Minecraft End User License Agreement as set forth by Mojang AB.
  // The Minecraft EULA can be viewed at https://account.mojang.com/documents/minecraft_eula
  // CanaryMod Team, PlayBlack, Visual Illusions Entertainment, CanaryLib, CanaryMod, and its contributors
  // are NOT affiliated with, endorsed, or sponsored by Mojang AB, makers of Minecraft.
  // "Minecraft" is a trademark of Notch Development AB
  // "CanaryMod" name is used with permission from FallenMoonNetwork.
  
  package org.knoxcraft.database.xml;
  
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.IOException;
  import java.io.RandomAccessFile;
  import java.lang.annotation.Annotation;
  import java.lang.reflect.Field;
  import java.nio.charset.Charset;
  import java.util.ArrayList;
  import java.util.Comparator;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  
  import org.jdom2.Content;
  import org.jdom2.DataConversionException;
  import org.jdom2.Document;
  import org.jdom2.Element;
  import org.jdom2.JDOMException;
  import org.jdom2.input.JDOMParseException;
  import org.jdom2.input.SAXBuilder;
  import org.jdom2.output.Format;
  import org.jdom2.output.XMLOutputter;
  import org.knoxcraft.database.Column;
  import org.knoxcraft.database.DataAccess;
  import org.knoxcraft.database.Database;
  import org.knoxcraft.database.Column.DataType;
  import org.knoxcraft.database.exceptions.DatabaseAccessException;
  import org.knoxcraft.database.exceptions.DatabaseReadException;
  import org.knoxcraft.database.exceptions.DatabaseTableInconsistencyException;
  import org.knoxcraft.database.exceptions.DatabaseWriteException;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  import com.google.common.collect.Maps;
  import com.google.common.io.Files;
  import com.google.inject.Inject;
  import com.mchange.v1.lang.BooleanUtils;
  
  /**
   * Represent access to an XML database
   *
   * @author Chris (damagefilter)
   */
  public class XmlDatabase extends Database {
  
      private Logger log=LoggerFactory.getLogger(XmlDatabase.class);
  
      private XmlDatabase() {
          File path = new File("db/");
  
          if (!path.exists()) {
              if (!path.mkdirs()) {
                  throw new ExceptionInInitializerError("Unable to create database directories... Please check your read/write permissions and try again");
              }
          }
      }
  
      private static XmlDatabase instance;
  
      public static XmlDatabase getInstance() {
          if (instance == null) {
              instance = new XmlDatabase();
          }
          return instance;
      }
  
      /**
       * Used to serialize the XML data into a bytestream
       */
      private XMLOutputter xmlSerializer = new XMLOutputter(Format.getPrettyFormat().setExpandEmptyElements(false).setOmitDeclaration(true).setOmitEncoding(true).setLineSeparator("\n"));
  
      private SAXBuilder fileBuilder = new SAXBuilder();
  
      /**
       * Used to store the table properties
       */
      private Map<String, Element> tableProperties = Maps.newConcurrentMap();
  
      @Override
      public void insert(DataAccess data) throws DatabaseWriteException {
          File file = new File("db/" + data.getName() + ".xml");
  
          if (!file.exists()) {
              try {
                  if (!file.createNewFile()) {
                      throw new DatabaseWriteException("Failed to create database XML file: " + data.getName());
                  }
              }
              catch (IOException e) {
                  throw new DatabaseWriteException(e.getMessage());
              }
          }
          Document dbTable;
  
          try {
              dbTable = verifyTable(file, data.getName());
              insertData(file, data, dbTable, true);
          }
          catch (JDOMException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
          catch (IOException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
          catch (DatabaseTableInconsistencyException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
      }
  
      @Override
      public void insertAll(List<DataAccess> data) throws DatabaseWriteException {
          DataAccess first = data.get(0);
          File file = new File("db/" + first.getName() + ".xml");
  
          if (!file.exists()) {
              try {
                  if (!file.createNewFile()) {
                      throw new DatabaseWriteException("Failed to create database XML file: " + first.getName());
                  }
              }
              catch (IOException e) {
                  throw new DatabaseWriteException(e.getMessage());
              }
          }
          Document dbTable;
  
          try {
              dbTable = verifyTable(file, first.getName());
              for (DataAccess da : data) {
                  insertData(file, da, dbTable, false);
              }
              write(file, dbTable);
          }
          catch (JDOMException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
          catch (IOException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
          catch (DatabaseTableInconsistencyException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
      }
  
      @Override
      public void load(DataAccess data, Map<String, Object> filters) throws DatabaseReadException {
          File file = new File("db/" + data.getName() + ".xml");
  
          if (!file.exists()) {
              throw new DatabaseReadException("Table " + data.getName() + " does not exist!");
          }
  
          try {
              Document table = verifyTable(file, data.getName());
              loadData(data, table, filters);
          }
          catch (JDOMException e) {
              throw new DatabaseReadException(e.getMessage(), e);
          }
          catch (IOException e) {
              throw new DatabaseReadException(e.getMessage(), e);
          }
          catch (DatabaseAccessException e) {
              throw new DatabaseReadException(e.getMessage(), e);
          }
      }
  
      @Override
      public void loadAll(DataAccess typeTemplate, List<DataAccess> datasets, Map<String, Object> filters) throws DatabaseReadException {
          File file = new File("db/" + typeTemplate.getName() + ".xml");
  
          if (!file.exists()) {
              throw new DatabaseReadException("Table " + typeTemplate.getName() + " does not exist!");
          }
  
          try {
              Document table = verifyTable(file, typeTemplate.getName());
              loadAllData(typeTemplate, datasets, table, filters);
          }
          catch (JDOMException e) {
              throw new DatabaseReadException(e.getMessage(), e);
          }
          catch (IOException e) {
              throw new DatabaseReadException(e.getMessage(), e);
          }
          catch (DatabaseAccessException e) {
              throw new DatabaseReadException(e.getMessage(), e);
          }
      }
  
      @Override
      public void update(DataAccess data, Map<String, Object> filters) throws DatabaseWriteException {
          File file = new File("db/" + data.getName() + ".xml");
  
          if (!file.exists()) {
              throw new DatabaseWriteException("Table " + data.getName() + " does not exist!");
          }
  
          try {
              Document table = verifyTable(file, data.getName());
              updateData(file, table, data, filters, true);
          }
          catch (JDOMException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
          catch (IOException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
          catch (DatabaseTableInconsistencyException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
      }
  
      @Override
      public void updateAll(DataAccess data, Map<DataAccess, Map<String, Object>> list) throws DatabaseWriteException {
  
          File file = new File("db/" + data.getName() + ".xml");
  
          if (!file.exists()) {
              throw new DatabaseWriteException("Table " + data.getName() + " does not exist!");
          }
  
          try {
              Document table = verifyTable(file, data.getName());
              for (DataAccess da : list.keySet()) {
                  updateData(file, table, da, list.get(da), false);
              }
              write(file, table);
          }
          catch (JDOMException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
          catch (IOException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
          catch (DatabaseTableInconsistencyException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
      }
  
      @Override
      public void remove(DataAccess data, Map<String, Object> filters) throws DatabaseWriteException {
          File file = new File("db/" + data.getName() + ".xml");
  
          if (!file.exists()) {
              throw new DatabaseWriteException("Table " + data.getName() + " does not exist!");
          }
  
          try {
              Document table = verifyTable(file, data.getName());
              removeData(file, table, filters, false);
          }
          catch (JDOMException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
          catch (IOException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
      }
  
      @Override
      public void removeAll(DataAccess data, Map<String, Object> filters) throws DatabaseWriteException {
          File file = new File("db/" + data.getName() + ".xml");
  
          if (!file.exists()) {
              throw new DatabaseWriteException("Table " + data.getName() + " does not exist!");
          }
  
          try {
              Document table = verifyTable(file, data.getName());
              removeData(file, table, filters, true);
          }
          catch (JDOMException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
          catch (IOException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
      }
  
      @Override
      public void updateSchema(DataAccess data) throws DatabaseWriteException {
          File file = new File("db/" + data.getName() + ".xml");
  
          if (!file.exists()) {
              try {
                  if (!file.createNewFile()) {
                      throw new DatabaseWriteException("Failed to create database XML file: " + data.getName());
                  }
              }
              catch (IOException e) {
                  throw new DatabaseWriteException(e.getMessage(), e);
              }
          }
          try {
              Document table = verifyTable(file, data.getName());
  
              if (table.getRootElement().getChild("tableProperties") == null) {
                  table.getRootElement().addContent(generateProperties(data));
              }
  
              HashSet<Column> tableLayout = data.getTableLayout();
  
              for (Column column : tableLayout) {
                  if (table.getRootElement().getChild("tableProperties").getChild(column.columnName()) == null) {
                      setPropertyFor(column, table.getRootElement().getChild("tableProperties"));
                  }
              }
              for (Element element : table.getRootElement().getChildren()) {
                  if (!element.getName().equals("tableProperties")) {
                      addFields(element, tableLayout);
                      removeFields(element, tableLayout);
  
                      // Clean out the old attribute data
                      for (Element child : element.getChildren()) {
                          child.getAttributes().clear();
                      }
                  }
              }
              write(file, table);
          }
          catch (JDOMException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
          catch (IOException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
          catch (DatabaseTableInconsistencyException e) {
              throw new DatabaseWriteException(e.getMessage(), e);
          }
      }
  
      private Document initFile(File file, String rootName) throws IOException {
          Document doc = new Document(new Element(rootName));
          write(file, doc);
          return doc;
      }
  
      /**
       * Adds new fields to the Element, according to the given layout set.
       *
       * @param element
       * @param layout
       */
      private void addFields(Element element, HashSet<Column> layout) {
          for (Column column : layout) {
              boolean found = false;
  
              for (Element child : element.getChildren()) {
                  if (child.getName().equals(column.columnName())) {
                      found = true;
                  }
              }
              if (!found) {
                  element.addContent(new Element(column.columnName()));
              }
          }
      }
  
      /**
       * Removes fields from the given element that are not contained in the given layout
       *
       * @param element
       * @param layout
       */
      private void removeFields(Element element, HashSet<Column> layout) {
          for (Element child : element.getChildren()) {
              boolean found = false;
  
              for (Column column : layout) {
                  if (child.getName().equals(column.columnName())) {
                      found = true;
                  }
              }
              if (!found) {
                  child.detach();
              }
          }
      }
  
      /**
       * Inserts data into the XML file. This does NOT update data.
       * It will create a new entry if there isn't the exact same already present
       *
       * @param file
       * @param data
       * @param dbTable
       *
       * @throws IOException
       * @throws DatabaseTableInconsistencyException
       */
      private void insertData(File file, DataAccess data, Document dbTable, boolean write) throws IOException, DatabaseTableInconsistencyException {
          HashMap<Column, Object> entry = data.toDatabaseEntryList();
  
          if (data.isInconsistent()) {
              // Just an extra precaution
              throw new DatabaseTableInconsistencyException("DataAccess is marked inconsistent!");
          }
          Element set = new Element("entry");
  
          for (Column column : entry.keySet()) {
  
              Element col = new Element(column.columnName());
              addToElement(dbTable, col, entry.get(column), column);
              set.addContent(col);
          }
          dbTable.getRootElement().addContent(set);
          if (write) {
              write(file, dbTable);
          }
      }
  
      /**
       * Updates an already existing element in the document.
       * IMPORTANT: the lengths of fields and content array must have been checked before this method is called!
       *
       * @param file
       * @param table
       * @param filters
       *
       * @throws IOException
       * @throws DatabaseTableInconsistencyException
       * @throws DatabaseWriteException
       */
      private void updateData(File file, Document table, DataAccess data, Map<String, Object> filters, boolean write) throws IOException, DatabaseTableInconsistencyException, DatabaseWriteException {
          boolean hasUpdated = false;
          String[] fields = new String[filters.size()];
          filters.keySet().toArray(fields); // We know those are strings
          for (Element element : table.getRootElement().getChildren()) {
              int equalFields = 0;
  
              for (String field : fields) {
                  Element child = element.getChild(field);
  
                  if (child != null) {
                      if (child.getText().equals(String.valueOf(filters.get(field)))) {
                          equalFields++;
                      }
                  }
              }
              if (equalFields != fields.length) {
                  continue; // Not the entry we're looking for
              }
  
              if (data.isInconsistent()) {
                  // Just an extra precaution
                  throw new DatabaseTableInconsistencyException("DataAccess is marked inconsistent!");
              }
  
  