docs: public void initialize() throws SQLException {
  		if (initialized) {
  			// just skip it if already initialized
  			return;
  		}
  
  		if (connectionSource == null) {
  			throw new IllegalStateException("connectionSource was never set on " + getClass().getSimpleName());
  		}
  
  		databaseType = connectionSource.getDatabaseType();
  		if (databaseType == null) {
  			throw new IllegalStateException(
  					"connectionSource is getting a null DatabaseType in " + getClass().getSimpleName());
  		}
  		if (tableConfig == null) {
  			tableInfo = new TableInfo<T, ID>(databaseType, dataClass);
  		} else {
  			tableConfig.extractFieldTypes(databaseType);
  			tableInfo = new TableInfo<T, ID>(databaseType, tableConfig);
  		}
  		statementExecutor = new StatementExecutor<T, ID>(databaseType, tableInfo, this);
  
  		/*
  		 * This is a bit complex. Initially, when we were configuring the field types, external DAO information would be
  		 * configured for auto-refresh, foreign BaseDaoEnabled classes, and foreign-collections. This would cause the
  		 * system to go recursive and for class loops, a stack overflow.
  		 * 
  		 * Then we fixed this by putting a level counter in the FieldType constructor that would stop the configurations
  		 * when we reach some recursion level. But this created some bad problems because we were using the DaoManager
  		 * to cache the created DAOs that had been constructed already limited by the level.
  		 * 
  		 * What we do now is have a 2 phase initialization. The constructor initializes most of the fields but then we
  		 * go back and call FieldType.configDaoInformation() after we are done. So for every DAO that is initialized
  		 * here, we have to see if it is the top DAO. If not we save it for dao configuration later.
  		 */
  		List<BaseDaoImpl<?, ?>> daoConfigList = daoConfigLevelLocal.get();
  		daoConfigList.add(this);
  		if (daoConfigList.size() > 1) {
  			// if we have recursed then just save the dao for later configuration
  			return;
  		}
  
  		try {
  			/*
  			 * WARNING: We do _not_ use an iterator here because we may be adding to the list as we process it and we'll
  			 * get exceptions otherwise. This is an ArrayList so the get(i) should be efficient.
  			 * 
  			 * Also, do _not_ get a copy of daoConfigLevel.doArray because that array may be replaced by another, larger
  			 * one during the recursion.
  			 */
  			for (int i = 0; i < daoConfigList.size(); i++) {
  				BaseDaoImpl<?, ?> dao = daoConfigList.get(i);
  
  				/*
  				 * Here's another complex bit. The first DAO that is being constructed as part of a DAO chain is not yet
  				 * in the DaoManager cache. If we continue onward we might come back around and try to configure this
  				 * DAO again. Forcing it into the cache here makes sure it won't be configured twice. This will cause it
  				 * to be stuck in twice when it returns out to the DaoManager but that's a small price to pay. This also
  				 * applies to self-referencing classes.
  				 */
  				DaoManager.registerDao(connectionSource, dao);
  
  				try {
  					// config our fields which may go recursive
  					for (FieldType fieldType : dao.getTableInfo().getFieldTypes()) {
  						fieldType.configDaoInformation(connectionSource, dao.getDataClass());
  					}
  				} catch (SQLException e) {
  					// unregister the DAO we just pre-registered
  					DaoManager.unregisterDao(connectionSource, dao);
  					throw e;
  				}
  
  				// it's now been fully initialized
  				dao.initialized = true;
  			}
  		} finally {
  			// if we throw we want to clear our class hierarchy here
  			daoConfigList.clear();
  			daoConfigLevelLocal.remove();
  		}
  	}