/* * Copyright (C) 2016 Civilian Framework. * * Licensed under the Civilian License (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.civilian-framework.org/license.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.civilian.type.fn; import java.text.ParseException; import java.util.function.Function; import org.civilian.text.keys.KeyType; import org.civilian.type.DiscreteType; import org.civilian.type.EnumType; import org.civilian.type.Type; /** * A TypeSerializer represents a certain schema of parsing and formatting * values from or to a string. */ // TODO docs public abstract class TypeSerializer { @FunctionalInterface public static interface Formatter<T> { public String format(Type<? extends T> type, T value, Object style); } @FunctionalInterface public static interface Parser<T> { public T parse(Type<T> type, String s) throws Exception; default public T parseEmpty() throws Exception { return null; } } public static interface SimpleParser<T> { public T parse(String s) throws Exception; } protected static final Parser<String> PARSE_STRING = new Parser<String>() { @Override public String parse(Type<String> type, String s) throws Exception { return s; } @Override public String parseEmpty() throws Exception { return ""; } }; protected TypeSerializer() { this(null); } protected TypeSerializer(TypeSerializer other) { formatMap_ = other != null ? other.formatMap_ : new TypeMap(); parseMap_ = other != null ? other.parseMap_ : new TypeMap(); } //------------------------- // format //------------------------- public <T> String format(Type<T> type, T value) { return format(type, value, null); } public <T> String format(Type<T> type, T value, Object style) { if (value == null) return formattedNull_; Formatter<T> fn = getFormatter(type); if (fn != null) return fn.format(type, value, style); throw new UnsupportedTypeException(this, "format", type); } public <T> Formatter<T> getFormatter(Type<T> type) { return formatMap_.get(type); } public <T> TypeMap.Builder<T> useFormatter(Formatter<T> fn) { return formatMap_.use(fn); } public <T> TypeMap.Builder<T> useSimpleFormatter(Function<T,String> simpleFn) { return useFormatter((t,v,s) -> simpleFn.apply(v)); } public <T> void useFormatNull(String nullValue) { formattedNull_ = nullValue; } protected <T> String formatDiscrete(Type<? extends T> type, T value, Object style) { @SuppressWarnings("unchecked") DiscreteType<T> dt = (DiscreteType<T>)type; return format(dt.getElementType(), value, style); } protected <T> String formatEnum(Type<? extends T> type, T value, Object style) { return ((Enum<?>)value).name(); } @SuppressWarnings("unchecked") protected <T> String formatKey(Type<? extends T> type, T value, Object style) { return ((KeyType<Object>)type).format(value); } //------------------------- // parse //------------------------- public <T> T parse(Type<T> type, String s) throws ParseException { try { if (s == null) return parseNull(type); Parser<T> fn = getParser(type); if (fn != null) return s.length() != 0 ? fn.parse(type, s) : fn.parseEmpty(); } catch (ParseException e) { throw e; } catch (Exception e) { ParseException pe = new ParseException(s, 0); pe.initCause(e); throw pe; } throw new UnsupportedTypeException(this, "parse", type); } public <T> T[] parseArray(Type<T> type, String s[]) throws ParseException { int n = s == null ? 0 : s.length; T[] result = type.createArray(n); for (int i=0; i<n; i++) result[i] = parse(type, s[i]); return result; } public <T> Parser<T> getParser(Type<T> type) { return parseMap_.get(type); } protected <T> T parseNull(Type<T> type) throws Exception { return null; } public <T> TypeMap.Builder<T> useParser(Parser<T> fn) { return parseMap_.use(fn); } public <T> TypeMap.Builder<T> useSimpleParser(SimpleParser<T> fn) { Parser<T> fn2 = (t,s) -> fn.parse(s); return useParser(fn2); } protected Character parseCharacter(Type<Character> type, String s) throws Exception { if (s.length() != 1) throw new ParseException("not a character: " + s, 0); return new Character(s.charAt(0)); }; protected <T> T parseDiscrete(Type<T> type, String s) throws Exception { DiscreteType<T> dt = (DiscreteType<T>)type; T value = parse(dt.getElementType(), s); if (dt.indexOf(value) < 0) throw new ParseException("not a valid entry '" + s + "'", 0); return value; } protected <T> T parseKey(Type<T> type, String s) throws Exception { return ((KeyType<T>)type).parse(s); } @SuppressWarnings("unchecked") protected <T> T parseEnum(Type<T> type, String s) throws Exception { EnumType<?> et = (EnumType<?>)type; return (T)Enum.valueOf(et.getJavaType(), s); } protected final TypeMap formatMap_; protected final TypeMap parseMap_; private String formattedNull_ = ""; }