package dbfit.util; import fit.Fixture; import fit.TypeAdapter; import static dbfit.util.SymbolUtil.isSymbolGetter; /* this class addresses several issues with parsing, and is used as a base for any other dbfit type adapters: * 1: TypeAdapter does not check the parse delegates directly when parsing, it relies on appropriate delegate * being selected when adapter is created; this creates problems for dbfit adapters which need to delegate parsing * to appropriate types, but access values from sql parameters etc * 2: this class encapsulates symbol access using << * 3: some db drivers will return different numeric types for the same column depending on use (in view, autogenerated..); * this adapter tries to fix inconsistent types first by casting, then by parsing if needed * */ public class ParseHelper { private Class<?> type; private Fixture fixture; public ParseHelper(Fixture fixture, Class<?> type) { this.type = type; this.fixture = fixture; } private Object tryToConvert(Object value) throws Exception { try { return type.cast(value); } catch (ClassCastException cex) { return parse(value.toString()); } } private Object parseSymbol(String s) throws Exception { Object value = dbfit.util.SymbolUtil.getSymbol(s); if (null == value || value.getClass().equals(type)) { return value; } // else try to convert try { return tryToConvert(value); } catch (Exception e) { throw new UnsupportedOperationException( "Incompatible types between symbol and cell value: expected " + type + "; but symbol is " + value.getClass(), e); } } public Object parse(String s) throws Exception { if (isSymbolGetter(s)) { return parseSymbol(s); } String trim = s.trim(); if (trim.toLowerCase().equals("null")) { return null; } if (type.equals(String.class) && Options.isFixedLengthStringParsing() && trim.startsWith("'") && trim.endsWith("'")) { return trim.substring(1, trim.length() - 1); } TypeAdapter ta = TypeAdapter.adapterFor(type); ta.init(fixture, type); return ta.parse(s); } }