package org.develnext.jphp.json.classes; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonIOException; import com.google.gson.JsonSyntaxException; import com.google.gson.stream.JsonWriter; import org.develnext.jphp.json.gson.MemoryDeserializer; import org.develnext.jphp.json.gson.MemorySerializer; import php.runtime.Memory; import php.runtime.common.HintType; import php.runtime.env.Environment; import php.runtime.ext.core.classes.format.WrapProcessor; import php.runtime.ext.core.classes.stream.Stream; import php.runtime.invoke.Invoker; import php.runtime.memory.*; import php.runtime.memory.helper.*; import php.runtime.reflection.ClassEntity; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.List; import static php.runtime.annotation.Reflection.*; @Name("php\\format\\JsonProcessor") public class JsonProcessor extends WrapProcessor { public static final int SERIALIZE_PRETTY_PRINT = 1; public static final int DESERIALIZE_AS_ARRAYS = 1024; protected GsonBuilder builder; protected Gson gson; protected MemorySerializer memorySerializer; protected MemoryDeserializer memoryDeserializer; protected final static List<Class<? extends Memory>> memClasses = new ArrayList<Class<? extends Memory>>() {{ add(Memory.class); add(NullMemory.class); add(UndefinedMemory.class); add(ReferenceMemory.class); add(TrueMemory.class); add(FalseMemory.class); add(LongMemory.class); add(DoubleMemory.class); add(ObjectMemory.class); add(ArrayMemory.class); add(BinaryMemory.class); add(CharMemory.class); add(KeyValueMemory.class); add(StringBuilderMemory.class); add(StringMemory.class); add(ArrayValueMemory.class); add(BinaryCharArrayMemory.class); add(CharArrayMemory.class); add(ShortcutMemory.class); add(VariadicMemory.class); }}; public JsonProcessor(Environment env, GsonBuilder builder) { super(env); this.builder = builder; this.gson = builder.create(); } public JsonProcessor(Environment env, ClassEntity clazz) { super(env, clazz); builder = new GsonBuilder(); memorySerializer = new MemorySerializer(); memorySerializer.setEnv(env); memoryDeserializer = new MemoryDeserializer(); memoryDeserializer.setEnv(env); for (Class<? extends Memory> el : memClasses) { builder.registerTypeAdapter(el, memorySerializer); } builder.registerTypeAdapter(Memory.class, memoryDeserializer); builder.disableHtmlEscaping(); gson = builder.create(); } @Signature(@Arg(value = "flags", optional = @Optional("0"))) public Memory __construct(Environment env, Memory... args) { int flags = args[0].toInteger(); if ((flags & SERIALIZE_PRETTY_PRINT) == SERIALIZE_PRETTY_PRINT) { builder.setPrettyPrinting(); } if ((flags & DESERIALIZE_AS_ARRAYS) == DESERIALIZE_AS_ARRAYS) { memoryDeserializer.setAssoc(true); } if (flags > 0) gson = builder.create(); return Memory.NULL; } @Override @Signature public Memory parse(Environment env, Memory... args) { Memory r; try { if (args[0].instanceOf(Stream.class)) { r = gson.fromJson(new InputStreamReader(Stream.getInputStream(env, args[0])), Memory.class); } else { r = gson.fromJson(args[0].toString(), Memory.class); } } catch (JsonSyntaxException e) { env.exception(ProcessorException.class, e.getMessage()); return Memory.NULL; } if (r == null) return Memory.NULL; return r; } @Override @Signature public Memory format(Environment env, Memory... args) { try { return StringMemory.valueOf(gson.toJson(args[0])); } catch (JsonIOException e) { env.exception(ProcessorException.class, e.getMessage()); return Memory.NULL; } } @Override @Signature public Memory formatTo(Environment env, Memory... args) { OutputStream outputStream = Stream.getOutputStream(env, args[1]); try { gson.toJson(args[0], Memory.class, new JsonWriter(new OutputStreamWriter(outputStream))); } catch (JsonIOException e) { env.exception(ProcessorException.class, e.getMessage()); return Memory.NULL; } finally { Stream.closeStream(env, outputStream); } return Memory.NULL; } @Signature({ @Arg("type"), @Arg(value = "callback", type = HintType.CALLABLE, optional = @Optional("null")) }) public Memory onSerialize(Environment env, Memory... args) { Memory.Type type = Memory.Type.of(args[0].toString()); if (type == null) throw new IllegalArgumentException("Invalid type - " + args[0]); MemorySerializer.Handler handler = null; if (!args[1].isNull()) { final Invoker invoker = Invoker.valueOf(env, env.trace(), args[1]); handler = new MemorySerializer.Handler() { @Override public Memory call(Environment env, Memory value) { return invoker.callNoThrow(value); } }; } memorySerializer.setTypeHandler(type, handler); return null; } @Signature({ @Arg("className"), @Arg(value = "callback", type = HintType.CALLABLE, optional = @Optional("null")) }) public Memory onClassSerialize(Environment env, Memory... args) { ClassEntity entity = env.fetchClass(args[0].toString(), true); if (entity == null) throw new IllegalArgumentException("Class not found - " + args[0]); MemorySerializer.Handler handler = null; if (!args[1].isNull()) { final Invoker invoker = Invoker.valueOf(env, env.trace(), args[1]); handler = new MemorySerializer.Handler() { @Override public Memory call(Environment env, Memory value) { return invoker.callNoThrow(value); } }; } memorySerializer.setClassHandler(entity.getName(), handler); return Memory.NULL; } }