com.jfireframework.codejson.function.WriterContext Maven / Gradle / Ivy
package com.jfireframework.codejson.function;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jfireframework.baseutil.collection.StringCache;
import com.jfireframework.baseutil.reflect.ReflectUtil;
import com.jfireframework.baseutil.smc.SmcHelper;
import com.jfireframework.baseutil.smc.compiler.JavaStringCompiler;
import com.jfireframework.baseutil.smc.model.CompilerModel;
import com.jfireframework.baseutil.smc.model.FieldModel;
import com.jfireframework.baseutil.smc.model.MethodModel;
import com.jfireframework.codejson.annotation.JsonIgnore;
import com.jfireframework.codejson.function.impl.write.IteratorWriter;
import com.jfireframework.codejson.function.impl.write.MapWriter;
import com.jfireframework.codejson.function.impl.write.StrategyMapWriter;
import com.jfireframework.codejson.function.impl.write.WriterAdapter;
import com.jfireframework.codejson.function.impl.write.array.BooleanArrayWriter;
import com.jfireframework.codejson.function.impl.write.array.ByteArrayWriter;
import com.jfireframework.codejson.function.impl.write.array.CharArrayWriter;
import com.jfireframework.codejson.function.impl.write.array.DoubleArrayWriter;
import com.jfireframework.codejson.function.impl.write.array.FloatArrayWriter;
import com.jfireframework.codejson.function.impl.write.array.IntArrayWriter;
import com.jfireframework.codejson.function.impl.write.array.LongArrayWriter;
import com.jfireframework.codejson.function.impl.write.array.ShortArrayWriter;
import com.jfireframework.codejson.function.impl.write.array.StringArrayWriter;
import com.jfireframework.codejson.function.impl.write.extra.ArrayListWriter;
import com.jfireframework.codejson.function.impl.write.extra.DateWriter;
import com.jfireframework.codejson.function.impl.write.extra.FileWriter;
import com.jfireframework.codejson.function.impl.write.wrapper.BooleanWriter;
import com.jfireframework.codejson.function.impl.write.wrapper.ByteWriter;
import com.jfireframework.codejson.function.impl.write.wrapper.CharacterWriter;
import com.jfireframework.codejson.function.impl.write.wrapper.DoubleWriter;
import com.jfireframework.codejson.function.impl.write.wrapper.FloatWriter;
import com.jfireframework.codejson.function.impl.write.wrapper.IntegerWriter;
import com.jfireframework.codejson.function.impl.write.wrapper.LongWriter;
import com.jfireframework.codejson.function.impl.write.wrapper.ShortWriter;
import com.jfireframework.codejson.function.impl.write.wrapper.StringWriter;
import com.jfireframework.codejson.methodinfo.MethodInfoBuilder;
import com.jfireframework.codejson.methodinfo.WriteMethodInfo;
import com.jfireframework.codejson.tracker.Tracker;
import com.jfireframework.codejson.util.MethodComparator;
import com.jfireframework.codejson.util.NameTool;
public class WriterContext
{
private static ConcurrentHashMap, JsonWriter> writerMap = new ConcurrentHashMap, JsonWriter>();
private static final Logger logger = LoggerFactory.getLogger(WriterContext.class);
private static AtomicInteger count = new AtomicInteger(1);
static
{
writerMap.put(String.class, new StringWriter());
writerMap.put(Double.class, new DoubleWriter());
writerMap.put(Float.class, new FloatWriter());
writerMap.put(Integer.class, new IntegerWriter());
writerMap.put(Long.class, new LongWriter());
writerMap.put(Short.class, new ShortWriter());
writerMap.put(Boolean.class, new BooleanWriter());
writerMap.put(Byte.class, new ByteWriter());
writerMap.put(Character.class, new CharacterWriter());
writerMap.put(int[].class, new IntArrayWriter());
writerMap.put(boolean[].class, new BooleanArrayWriter());
writerMap.put(long[].class, new LongArrayWriter());
writerMap.put(short[].class, new ShortArrayWriter());
writerMap.put(byte[].class, new ByteArrayWriter());
writerMap.put(float[].class, new FloatArrayWriter());
writerMap.put(double[].class, new DoubleArrayWriter());
writerMap.put(char[].class, new CharArrayWriter());
writerMap.put(String[].class, new StringArrayWriter());
writerMap.put(ArrayList.class, new ArrayListWriter());
writerMap.put(Date.class, new DateWriter());
writerMap.put(File.class, new FileWriter());
writerMap.put(java.sql.Date.class, new DateWriter());
}
public static void write(Object entity, StringCache cache)
{
if (entity == null)
{
cache.append("null");
}
else
{
JsonWriter writer = getWriter(entity.getClass());
try
{
writer.write(entity, cache, null, null);
}
catch (Throwable e)
{
e.printStackTrace();
}
}
}
public static JsonWriter getWriter(Class> ckass)
{
JsonWriter writer = writerMap.get(ckass);
if (writer == null)
{
try
{
writer = (JsonWriter) createWriter(ckass, null).newInstance();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
writerMap.putIfAbsent(ckass, writer);
}
return writer;
}
protected static JsonWriter getWriter(Class> ckass, WriteStrategy strategy)
{
// 这个方法每次都必须重新生成新的输出类。实际上这个方法并不是给用户直接调用的。而是给策略模式进行writer生成的。
// 如果在这里使用writerMap进行判断,就会导致一种情况:前面已经进行过该类的输出生成了,现在有个新的策略,策略就无法生效。因为不会生成新的输出类
Class> result = createWriter(ckass, strategy);
try
{
Constructor> constructor = result.getConstructor(WriteStrategy.class);
return (JsonWriter) constructor.newInstance(strategy);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
/**
* 创建一个输出类cklas的jsonwriter
*
* @param ckass
* @return
*/
private static Class> createWriter(Class> ckass, WriteStrategy strategy)
{
if (ckass.isArray())
{
return implWriter(implArrayWriterMethod(ckass, strategy), ckass, strategy);
}
else if (Iterable.class.isAssignableFrom(ckass))
{
return IteratorWriter.class;
}
else if (Map.class.isAssignableFrom(ckass))
{
if (strategy == null)
{
return MapWriter.class;
}
else
{
return StrategyMapWriter.class;
}
}
else
{
return implWriter(implWriteMethod(ckass, strategy), ckass, strategy);
}
}
private static String implWriteMethod(Class> ckass, WriteStrategy strategy)
{
StringCache cache = new StringCache();
cache.append("{\r\nStringCache cache = (StringCache)$1;\r\n");
cache.append("Tracker _$tracker = (Tracker)$3;\r\n");
String entityName = "entity" + count.incrementAndGet();
cache.append(SmcHelper.getTypeName(ckass) + " " + entityName + " =(" + SmcHelper.getTypeName(ckass) + " )$0;\r\n");
if (strategy != null && strategy.isUseTracker())
{
cache.append("int _$reIndex = _$tracker.indexOf($0);\r\n");
}
cache.append("cache.append('{');\r\n");
Method[] methods = ReflectUtil.listGetMethod(ckass);
Arrays.sort(methods, new MethodComparator());
for (Method each : methods)
{
if (needIgnore(each, strategy))
{
continue;
}
WriteMethodInfo methodInfo = MethodInfoBuilder.buildWriteMethodInfo(each, strategy, entityName);
cache.append(methodInfo.getOutput());
}
cache.append("if(cache.isCommaLast())\r\n{\r\n\tcache.deleteLast();\r\n}\r\n");
cache.append("cache.append('}');\r\n}");
return cache.toString();
}
private static Class> implWriter(String methodBody, Class> ckass, WriteStrategy strategy)
{
try
{
CompilerModel compilerModel = new CompilerModel("JsonWriter_" + count.getAndIncrement(), WriterAdapter.class);
compilerModel.addImport(StringCache.class, WriterContext.class, Tracker.class, Iterator.class, Map.class, Set.class, Entry.class, JsonWriter.class);
if (strategy != null)
{
createStrategyConstructor(compilerModel);
}
Method method = WriterAdapter.class.getMethod("write", Object.class, StringCache.class, Object.class, Tracker.class);
MethodModel methodModel = new MethodModel(method);
methodModel.setBody(methodBody);
compilerModel.putMethod(method, methodModel);
logger.trace("{}创建的源码是\r{}\r", ckass.getName(), compilerModel.toStringWithLineNo());
JavaStringCompiler compiler = new JavaStringCompiler();
return compiler.compile(compilerModel, ckass.getClassLoader());
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
private static void createStrategyConstructor(CompilerModel model)
{
model.addField(new FieldModel("writeStrategy", WriteStrategy.class));
model.addConstructor("this.writeStrategy = $0;", WriteStrategy.class);
}
private static boolean needIgnore(Method method, WriteStrategy strategy)
{
String fieldName = ReflectUtil.getFieldNameFromMethod(method);
if (method.isAnnotationPresent(JsonIgnore.class) && method.getAnnotation(JsonIgnore.class).force())
{
return true;
}
try
{
Field field = method.getDeclaringClass().getDeclaredField(fieldName);
if (field.isAnnotationPresent(JsonIgnore.class) && field.getAnnotation(JsonIgnore.class).force())
{
return true;
}
}
catch (Exception e)
{
}
if (strategy != null)
{
if (strategy.ignore(method.getDeclaringClass().getName() + '.' + fieldName))
{
return true;
}
else
{
return false;
}
}
if (method.isAnnotationPresent(JsonIgnore.class))
{
return true;
}
try
{
Field field = method.getDeclaringClass().getDeclaredField(fieldName);
if (field.isAnnotationPresent(JsonIgnore.class))
{
return true;
}
else
{
return false;
}
}
catch (Exception e)
{
return false;
}
}
private static String implArrayWriterMethod(Class> targetClass, WriteStrategy strategy)
{
Class> rootType = targetClass;
int dim = 0;
while (rootType.isArray())
{
dim++;
rootType = rootType.getComponentType();
}
String rootName = rootType.getName();
String str;
if (strategy == null)
{
str = "{\r\n\t" + NameTool.buildDimTypeName(rootName, dim) + " array" + dim + " = (" + NameTool.buildDimTypeName(rootName, dim) + ")$0;\r\n";
str += "\tStringCache cache = (StringCache)$1;\r\n";
str += "\tcache.append('[');\r\n";
str += "\tint l" + dim + " = array" + dim + ".length;\r\n";
String bk = "\t";
for (int i = dim; i > 1; i--)
{
int next = i - 1;
str += bk + "for(int i" + i + " = 0;i" + i + " 1; i--)
{
str += bk + "if(cache.isCommaLast()){cache.deleteLast();}\r\n";
str += bk + "cache.append(']');\r\n";
str += bk + "cache.append(',');\r\n";
bk = bk.substring(0, bk.length() - 1);
str += bk + "}\r\n";
}
str += bk + "if(cache.isCommaLast()){cache.deleteLast();}\r\n";
str += bk + "cache.append(']');\r\n";
str += "}";
}
else
{
if (strategy.isUseTracker())
{
str = "{\r\n\t" + NameTool.buildDimTypeName(rootName, dim) + " array" + dim + " = (" + NameTool.buildDimTypeName(rootName, dim) + ")$0;\r\n";
str += "\tStringCache cache = (StringCache)$1;\r\n";
str += "\tTracker _$tracker = (Tracker)$3;\r\n";
str += "\tint _$reIndex = _$tracker.indexOf($0);\r\n";
str += "\tcache.append('[');\r\n";
str += "\tint l" + dim + " = array" + dim + ".length;\r\n";
String bk = "\t";
for (int i = dim; i > 1; i--)
{
int next = i - 1;
int pre = i + 1;
str += bk + "for(int i" + i + " = 0;i" + i + " 1; i--)
{
str += bk + "if(cache.isCommaLast()){cache.deleteLast();}\r\n";
str += bk + "cache.append(']');\r\n";
str += bk + "cache.append(',');\r\n";
bk = bk.substring(0, bk.length() - 1);
str += bk + "}\r\n";
}
str += bk + "if(cache.isCommaLast()){cache.deleteLast();}\r\n";
str += bk + "cache.append(']');\r\n";
str += "}";
}
else
{
str = "{\r\n\t" + NameTool.buildDimTypeName(rootName, dim) + " array" + dim + " = (" + NameTool.buildDimTypeName(rootName, dim) + ")$0;\r\n";
str += "\tStringCache cache = (StringCache)$1;\r\n";
str += "\tcache.append('[');\r\n";
str += "\tint l" + dim + " = array" + dim + ".length;\r\n";
String bk = "\t";
for (int i = dim; i > 1; i--)
{
int next = i - 1;
str += bk + "for(int i" + i + " = 0;i" + i + " 1; i--)
{
str += bk + "if(cache.isCommaLast()){cache.deleteLast();}\r\n";
str += bk + "cache.append(']');\r\n";
str += bk + "cache.append(',');\r\n";
bk = bk.substring(0, bk.length() - 1);
str += bk + "}\r\n";
}
str += bk + "if(cache.isCommaLast()){cache.deleteLast();}\r\n";
str += bk + "cache.append(']');\r\n";
str += "}";
}
}
return str;
}
public static void putwriter(Class> cklass, JsonWriter jsonWriter)
{
writerMap.put(cklass, jsonWriter);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy