
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 extends Enum> 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 extends Codec> kvCodec = $.classForName("org.osgl.util.KVCodec");
ValueObject.register($.newInstance(kvCodec));
} catch (Exception e) {
// ignore
}
try {
Class extends Codec> jsonObjectCodec = $.classForName("org.osgl.util.FastJsonObjectCodec");
ValueObject.register($.newInstance(jsonObjectCodec));
} catch (Exception e) {
// ignore
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy