All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.osgl.util.ValueObject Maven / Gradle / Ivy

The newest version!
package org.osgl.util;

/*-
 * #%L
 * Java Tool
 * %%
 * Copyright (C) 2014 - 2017 OSGL (Open Source General Library)
 * %%
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 * 
 * 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.
 * #L%
 */

import com.alibaba.fastjson.JSON;
import org.osgl.$;

import java.io.Serializable;
import java.util.Map;

/**
 * A {@code ValueObject} encapsulate data of simple types in common Java application.
 * 

Simple type here refers to

*
    *
  • Primary types
  • *
  • String
  • *
  • Enum
  • *
  • Types with {@link Codec} {@link #register(Codec) registered}
  • *
*

* {@code ValueObject} is immutable *

*/ public class ValueObject implements Serializable { private static final long serialVersionUID = -6103505642730947577L; public interface Codec { Class targetClass(); T parse(String s); String toString(T o); String toJSONString(T o); } private static Map codecRegistry = C.newMap(); @SuppressWarnings("unchecked") private static enum Type { BOOL() { @Override T get(ValueObject vo) { return (T) vo.blVal; } @Override void set(Object o, ValueObject vo) { vo.blVal = $.cast(o); } @Override T decode(String s, Class type) { E.illegalArgumentIf(boolean.class != type || Boolean.class != type); return (T) Boolean.valueOf(s); } }, BYTE() { @Override T get(ValueObject vo) { return (T) vo.byVal; } @Override void set(Object o, ValueObject vo) { vo.byVal = $.cast(o); } @Override T decode(String s, Class type) { E.illegalArgumentIf(byte.class != type || Byte.class != type); return (T) Byte.valueOf(s); } }, CHAR() { @Override T get(ValueObject vo) { return (T) vo.chVal; } @Override void set(Object o, ValueObject vo) { vo.chVal = $.cast(o); } @Override String toJSONString(ValueObject vo) { return S.builder("\"").append(toString(vo)).append("\"").toString(); } @Override T decode(String s, Class type) { E.illegalArgumentIf(char.class != type || Character.class != type); return (T) Character.valueOf(s.charAt(0)); } }, SHORT() { @Override T get(ValueObject vo) { return (T) vo.shVal; } @Override void set(Object o, ValueObject vo) { vo.shVal = $.cast(o); } @Override T decode(String s, Class type) { E.illegalArgumentIf(short.class != type || Short.class != type); return (T) Short.valueOf(s); } }, INT() { @Override T get(ValueObject vo) { return (T) vo.iVal; } @Override void set(Object o, ValueObject vo) { vo.iVal = $.cast(o); } @Override T decode(String s, Class type) { E.illegalArgumentIf(int.class != type || Integer.class != type); return (T) Integer.valueOf(s); } }, FLOAT() { @Override T get(ValueObject vo) { return (T) vo.fVal; } @Override void set(Object o, ValueObject vo) { vo.fVal = $.cast(o); } @Override T decode(String s, Class type) { E.illegalArgumentIf(float.class != type || Float.class != type); return (T) Float.valueOf(s); } }, LONG() { @Override T get(ValueObject vo) { return (T) vo.lVal; } @Override void set(Object o, ValueObject vo) { vo.lVal = $.cast(o); } @Override T decode(String s, Class type) { E.illegalArgumentIf(long.class != type || Long.class != type); return (T) Long.valueOf(s); } }, DOUBLE() { @Override T get(ValueObject vo) { return (T) vo.dVal; } @Override void set(Object o, ValueObject vo) { vo.dVal = $.cast(o); } @Override T decode(String s, Class type) { E.illegalArgumentIf(double.class != type || Double.class != type); return (T) Double.valueOf(s); } }, STRING() { @Override T get(ValueObject vo) { return (T) vo.sVal; } @Override void set(Object o, ValueObject vo) { vo.sVal = S.string(o); } @Override String toJSONString(ValueObject vo) { String string = toString(vo); if (string == null || string.length() == 0) { return "\"\""; } char c; int i; int len = string.length(); StringBuilder sb = new StringBuilder(len + 4); String t; sb.append('"'); for (i = 0; i < len; i += 1) { c = string.charAt(i); switch (c) { case '\\': case '"': sb.append('\\'); sb.append(c); break; case '/': // if (b == '<') { sb.append('\\'); // } sb.append(c); break; case '\b': sb.append("\\b"); break; case '\t': sb.append("\\t"); break; case '\n': sb.append("\\n"); break; case '\f': sb.append("\\f"); break; case '\r': sb.append("\\r"); break; default: if (c < ' ') { t = "000" + Integer.toHexString(c); sb.append("\\u" + t.substring(t.length() - 4)); } else { sb.append(c); } } } sb.append('"'); return sb.toString(); } @Override T decode(String s, Class type) { E.illegalArgumentIf(String.class != type); return (T) s; } }, ENUM() { @Override T get(ValueObject vo) { return (T) vo.eVal; } @Override void set(Object o, ValueObject vo) { vo.eVal = $.cast(o); } @Override String toJSONString(ValueObject vo) { return S.builder("\"").append(toString(vo)).append("\"").toString(); } @Override T decode(String s, Class type) { E.illegalArgumentIf(!Enum.class.isAssignableFrom(type)); Class typedType = $.cast(type); return (T) Enum.valueOf(typedType, s); } }, UDF() { @Override T get(ValueObject vo) { return $.cast(vo.udf); } @Override void set(Object o, ValueObject vo) { vo.udf = o; } @Override T decode(String s, Class type) { Codec codec = findCodec(type); return (T)(null == codec ? JSON.parseObject(s, type) : codec.parse(s)) ; } @Override String encode(Object o) { Codec codec = findCodec(o.getClass()); return null == codec ? JSON.toJSONString(o) : codec.toString(o); } @Override String toString(ValueObject vo) { Class objType = vo.udf.getClass(); Codec codec = findCodec(objType); return null != codec ? codec.toString(vo.udf) : super.toString(vo); } @Override String toJSONString(ValueObject vo) { Class objType = vo.udf.getClass(); Codec codec = findCodec(objType); return null != codec ? codec.toJSONString(vo.udf) : super.toJSONString(vo); } private Codec findCodec(Class c) { Codec codec = codecRegistry.get(c); if (null != codec) { return codec; } Class[] ifs = c.getInterfaces(); if (null != ifs) { for (Class c0 : ifs) { codec = findCodec(c0); if (null != codec) { return codec; } } } Class sc = c.getSuperclass(); return null == sc ? null : findCodec(sc); } }; abstract T get(ValueObject vo); abstract void set(Object o, ValueObject vo); String toString(ValueObject vo) { Object o = get(vo); return S.string(o); } String toJSONString(ValueObject vo) { return toString(vo); } abstract T decode(String s, Class type); String encode(Object o) { return S.string(o); } } private transient Type type; private Boolean blVal; private Byte byVal; private Character chVal; private Short shVal; private Integer iVal; private Float fVal; private Long lVal; private Double dVal; private String sVal; private Enum eVal; private Object udf; public ValueObject() { this(""); } public ValueObject(boolean b) { blVal = b; type = Type.BOOL; } public ValueObject(byte b) { byVal = b; type = Type.BYTE; } public ValueObject(char c) { chVal = c; type = Type.CHAR; } public ValueObject(short s) { shVal = s; type = Type.SHORT; } public ValueObject(int i) { iVal = i; type = Type.INT; } public ValueObject(float f) { fVal = f; type = Type.FLOAT; } public ValueObject(long l) { lVal = l; type = Type.LONG; } public ValueObject(double d) { dVal = d; type = Type.DOUBLE; } public ValueObject(String s) { sVal = $.requireNotNull(s); type = Type.STRING; } public ValueObject(CharSequence s) { sVal = s.toString(); type = Type.STRING; } public ValueObject(Enum e) { eVal = e; type = Type.ENUM; } public ValueObject(Object o) { if (o instanceof ValueObject) { ValueObject that = (ValueObject) o; type = that.type(); type.set(that.value(), this); } else { type = typeOf(o); type.set(o, this); } } public ValueObject(ValueObject copy) { type = copy.type(); type.set(copy.value(), this); } public boolean booleanValue() { return blVal; } public byte byteValue() { return byVal; } public char charValue() { return chVal; } public short shortValue() { return shVal; } public int intValue() { return iVal; } public float floatValue() { return fVal; } public long longValue() { return lVal; } public double doubleValue() { return dVal; } public String stringValue() { return $.requireNotNull(sVal); } public T enumValue() { return $.cast(eVal); } public T value() { return type().get(this); } public boolean isUDF() { Type type = type(); return type == Type.UDF || type == Type.ENUM; } @Override public int hashCode() { Object v = type().get(this); return $.hc(v); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof ValueObject) { ValueObject that = (ValueObject) obj; return $.eq(that.type().get(that), this.type().get(this)); } return false; } @Override public String toString() { return type().toString(this); } public String toJSONString() { return type().toJSONString(this); } public static void register(Codec codec) { codecRegistry.put(codec.targetClass(), codec); } public static void unregister(Codec codec) { codecRegistry.remove(codec.targetClass()); } /** * Decode a object instance from a string with given target object type * * @param string the string encoded the value of the instance * @param targetType the class of the instance decoded from the string * @param the generic type of the instance * @return the instance decoded */ public static T decode(String string, Class targetType) { Type type = typeOf(targetType); return type.decode(string, targetType); } /** * Encode a object into a String * * @param o the object to be encoded * @return the encoded string representation of the object * @throws IllegalArgumentException when object is a UDF type and Codec is not registered */ public static String encode(Object o) { Type type = typeOf(o); return type.encode(o); } public static ValueObject of(Object o) { if (o instanceof ValueObject) { return $.cast(o); } return new ValueObject(o); } private Type type() { if (null == type) { type = findType(); } return type; } private Type findType() { if (sVal != null) { type = Type.STRING; } if (iVal != null) { return Type.INT; } if (dVal != null) { return Type.DOUBLE; } if (eVal != null) { return Type.ENUM; } if (lVal != null) { return Type.LONG; } if (fVal != null) { return Type.FLOAT; } if (blVal != null) { return Type.BOOL; } if (byVal != null) { return Type.BYTE; } if (chVal != null) { return Type.CHAR; } if (shVal != null) { return Type.SHORT; } return Type.UDF; } private static Type typeOf(Object o) { if (null == o) { return Type.STRING; } if (o instanceof CharSequence) { return Type.STRING; } if (o instanceof Integer) { return Type.INT; } if (o instanceof Boolean) { return Type.BOOL; } if (o instanceof Enum) { return Type.ENUM; } if (o instanceof Double) { return Type.DOUBLE; } if (o instanceof Long) { return Type.LONG; } if (o instanceof Float) { return Type.FLOAT; } if (o instanceof Character) { return Type.CHAR; } if (o instanceof Byte) { return Type.BYTE; } if (o instanceof Short) { return Type.SHORT; } return Type.UDF; } private static Type typeOf(Class c) { E.NPE(c); if (String.class.isAssignableFrom(c)) { return Type.STRING; } if (Integer.class.isAssignableFrom(c) || int.class.isAssignableFrom(c)) { return Type.INT; } if (Boolean.class.isAssignableFrom(c) || boolean.class.isAssignableFrom(c)) { return Type.BOOL; } if (Enum.class.isAssignableFrom(c)) { return Type.ENUM; } if (Double.class.isAssignableFrom(c) || double.class.isAssignableFrom(c)) { return Type.DOUBLE; } if (Long.class.isAssignableFrom(c) || long.class.isAssignableFrom(c)) { return Type.LONG; } if (Character.class.isAssignableFrom(c) || char.class.isAssignableFrom(c)) { return Type.CHAR; } if (Byte.class.isAssignableFrom(c) || byte.class.isAssignableFrom(c)) { return Type.BYTE; } if (Short.class.isAssignableFrom(c) || short.class.isAssignableFrom(c)) { return Type.SHORT; } return Type.UDF; } static { ValueObject.register(BigDecimalValueObjectCodec.INSTANCE); ValueObject.register(BigIntegerValueObjectCodec.INSTANCE); ValueObject.register(KeywordValueObjectCodec.INSTANCE); try { Class kvCodec = $.classForName("org.osgl.util.KVCodec"); ValueObject.register($.newInstance(kvCodec)); } catch (Exception e) { // ignore } try { Class jsonObjectCodec = $.classForName("org.osgl.util.FastJsonObjectCodec"); ValueObject.register($.newInstance(jsonObjectCodec)); } catch (Exception e) { // ignore } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy