package com.jrjackson; import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyObject; import org.jruby.RubyString; import org.jruby.RubySymbol; import org.jruby.RubyHash; import org.jruby.anno.JRubyMethod; import org.jruby.anno.JRubyModule; import org.jruby.java.addons.IOJavaAddons; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import java.io.InputStream; import java.io.IOException; import java.util.*; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.core.JsonProcessingException; @JRubyModule(name = "JrJacksonRaw") public class JrJacksonRaw extends RubyObject { public JrJacksonRaw(Ruby ruby, RubyClass metaclass) { super(ruby, metaclass); } private static boolean flagged(RubyHash opts, RubySymbol key) { Object val = opts.get(key); if (val == null) { return false; } return (Boolean) val; } // deserialize @JRubyMethod(module = true, name = {"parse", "load"}, required = 2) public static IRubyObject parse(ThreadContext context, IRubyObject self, IRubyObject arg, IRubyObject opts) throws IOException { RubyHash options = null; ObjectMapper local = null; Ruby _ruby = context.getRuntime(); if (opts != context.nil) { options = opts.convertToHash(); if (flagged(options, RubyUtils.rubySymbol(_ruby, "symbolize_keys"))) { local = RubyJacksonModule.mappedAs("sym", _ruby); } if (flagged(options, RubyUtils.rubySymbol(_ruby, "raw"))) { local = RubyJacksonModule.mappedAs("raw", _ruby); } if (local == null) { local = RubyJacksonModule.mappedAs("str", _ruby); } if (flagged(options, RubyUtils.rubySymbol(_ruby, "use_bigdecimal"))) { local.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS); } else { local.disable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS); } } else { local = RubyJacksonModule.mappedAs("str", _ruby); } return _parse(context, arg, local); } @JRubyMethod(module = true, name = {"parse_raw", "load_raw"}, required = 1) public static IRubyObject parse_raw(ThreadContext context, IRubyObject self, IRubyObject arg) throws IOException { ObjectMapper mapper = RubyJacksonModule.mappedAs("raw", context.getRuntime()); return _parse(context, arg, mapper); } @JRubyMethod(module = true, name = {"parse_sym", "load_sym"}, required = 1) public static IRubyObject parse_sym(ThreadContext context, IRubyObject self, IRubyObject arg) throws IOException { ObjectMapper mapper = RubyJacksonModule.mappedAs("sym", context.getRuntime()); return _parse(context, arg, mapper); } @JRubyMethod(module = true, name = {"parse_str", "load_str"}, required = 1) public static IRubyObject parse_str(ThreadContext context, IRubyObject self, IRubyObject arg) throws IOException { ObjectMapper mapper = RubyJacksonModule.mappedAs("str", context.getRuntime()); return _parse(context, arg, mapper); } private static IRubyObject _parse(ThreadContext context, IRubyObject arg, ObjectMapper mapper) throws IOException { Ruby ruby = context.getRuntime(); try { Object o; if (arg instanceof RubyString) { o = mapper.readValue( ((RubyString)arg).getBytes(), Object.class ); } else { // must be an IO object then IRubyObject stream = IOJavaAddons.AnyIO.any_to_inputstream(context, arg); o = mapper.readValue((InputStream)stream.toJava(InputStream.class), Object.class); } return RubyUtils.rubyObject(ruby, o); } catch (JsonProcessingException e) { throw ParseError.newParseError(ruby, e.getLocalizedMessage()); } catch (IOException e) { throw ruby.newIOError(e.getLocalizedMessage()); } } // serialize @JRubyMethod(module = true, name = {"generate", "dump"}, required = 1) public static IRubyObject generate(ThreadContext context, IRubyObject self, IRubyObject arg) throws IOException, JsonProcessingException { Ruby _ruby = context.getRuntime(); Object obj = arg.toJava(Object.class); try { ObjectMapper mapper = RubyJacksonModule.mappedAs("raw", _ruby); String s = mapper.writeValueAsString(obj); return RubyUtils.rubyString(_ruby, s); } catch (JsonProcessingException e) { throw ParseError.newParseError(_ruby, e.getLocalizedMessage()); } catch (IOException e) { throw _ruby.newIOError(e.getLocalizedMessage()); } } }