Java – How to make method calls more generic when dealing with multiple class types

designjavaobject-oriented

I have a loader class that executes data loading functions at boot-time for my application to give me test data.

The idea is pretty simple, I'm reading in XML data, using JaxB to turn it into a POJO and then persisting the POJO using JPA repo.

Here is my code (pretty small):

Looking at the parseFile method, I create a new JaxB instance but it requires the UserContainer class. The problem is, I want to reuse this method for potentially infinitely many containers. What is the best way to refactor this to make it more generic?

I was hoping to avoid the need to pass around a reference to the class type in each subsequent method.

@Override
  public void onApplicationEvent(ApplicationReadyEvent event) {
    LOGGER.log(Level.INFO, "Preparing to load data into database");

    try {
      loadAndStoreUserData();
    } catch (IOException | JAXBException e) {
      LOGGER.log(Level.INFO, "Unable to store user data");
      e.printStackTrace();
    }
  }

  /**
   * Loads up any test data from resources and stores into embedded DB for test env
   * @throws IOException
   * @throws JAXBException
   */
  private void loadAndStoreUserData() throws IOException, JAXBException {
    LOGGER.log(Level.INFO, "User data table being added to database");
    UserContainer userData = (UserContainer) ingestFromFile("testDatabase/users.xml", UserContainer);
    userData.getUsers().stream().forEach(userRepo::save);
  }

  /**
   * Read in file from static resources dir
   * @param fileName
   * @return
   * @throws IOException
   * @throws JAXBException
   */
  private Object ingestFromFile(String fileName, Object classReference) throws IOException, JAXBException {
   Resource resource =  new ClassPathResource(fileName);
   return parseFile(resource.getFile());
  }

  /**
   * Takes input file from disk and parsed out contents by marshaling XML -> POJO
   * @param inputFile
   * @return
   * @throws JAXBException
   */
  private Object parseFile(File inputFile) throws JAXBException {
    JAXBContext jaxbContext = JAXBContext.newInstance(UserContainer.class);
    Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
    return jaxbUnmarshaller.unmarshal(inputFile);
  }
}

Best Answer

Why can't you just pass the a container class reference? Imagine:

private <T> T parseFile(String fileName, Class<T> targetClass) {
    JAXBContext jaxbContext = JAXBContext.newInstance(targetClass);
    Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
    // The cast must be prety safe.
    return targetClass.cast(jaxbUnmarshaller.unmarshal(inputFile));
}
Related Topic