Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions Mavenfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,15 @@ packaging :jar

properties 'project.build.sourceEncoding' => 'UTF-8',
# create a pom.xml from this here
'polyglot.dump.pom' => 'pom.xml'
'polyglot.dump.pom' => 'pom.xml',
'maven.compiler.release' => '11'

jar 'junit:junit', '4.13.2', :scope => :test

jar 'org.jruby:jruby', '9.3.14.0', :scope => :provided
jar 'org.jruby:jruby', '9.4.14.0', :scope => :provided

plugin :compiler, '3.1', :source => '1.8', :target => '1.8',
plugin :compiler, '3.11.0', :release => '11',
:showDeprecation => false,
:showWarnings => false,
:executable => '${JAVA_HOME}/bin/javac',
:fork => true
:showWarnings => false

plugin :surefire, '2.17', :skipTests => true
plugin :surefire, '2.17', :skipTests => false
66 changes: 0 additions & 66 deletions benchmarking/sourced.rb

This file was deleted.

5 changes: 4 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
v0.4.21
v0.5.0
Upgrade jackson and jackson-databind to v2.21.2
Require JRuby 9.4.14.0 and Java 11 toolchain for builds
Drop legacy Gson benchmarks and dependency
Add bigdecimal as a runtime dependency for JRuby 10 / Ruby 3.4+ compatibility
Add GitHub Actions CI workflow

Expand Down
3 changes: 2 additions & 1 deletion jrjackson.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ Gem::Specification.new do |s|
s.add_development_dependency 'jar-dependencies', '>= 0.3.2'

jackson_version = JrJackson::BuildInfo.jackson_version
jackson_annotations_version = JrJackson::BuildInfo.jackson_annotations_version
jackson_databind_version = JrJackson::BuildInfo.jackson_databind_version
s.requirements << "jar com.fasterxml.jackson.core:jackson-core, #{jackson_version}"
s.requirements << "jar com.fasterxml.jackson.core:jackson-annotations, #{jackson_version}"
s.requirements << "jar com.fasterxml.jackson.core:jackson-annotations, #{jackson_annotations_version}"
s.requirements << "jar com.fasterxml.jackson.core:jackson-databind, #{jackson_databind_version}"
s.requirements << "jar com.fasterxml.jackson.module:jackson-module-afterburner, #{jackson_version}"

Expand Down
16 changes: 10 additions & 6 deletions lib/jrjackson/build_info.rb
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
module JrJackson
module BuildInfo
def self.version
'0.4.21'
'0.5.0'
end

def self.release_date
'2026-03-16'
'2026-04-17'
end

def self.files
repo_files.concat(generated_jar_files).concat(generated_files)
end

def self.jackson_version
'2.15.4'
'2.21.2'
end

def self.jackson_annotations_version
'2.21'
Comment thread
jsvd marked this conversation as resolved.
end

def self.jackson_databind_version
'2.15.4'
'2.21.2'
end

def self.jar_version
'1.2.37'
'1.3.0'
end

private
Expand All @@ -36,7 +40,7 @@ def self.repo_files

def self.generated_jar_files
[
"lib/com/fasterxml/jackson/core/jackson-annotations/#{jackson_version}/jackson-annotations-#{jackson_version}.jar",
"lib/com/fasterxml/jackson/core/jackson-annotations/#{jackson_annotations_version}/jackson-annotations-#{jackson_annotations_version}.jar",
"lib/com/fasterxml/jackson/core/jackson-core/#{jackson_version}/jackson-core-#{jackson_version}.jar",
"lib/com/fasterxml/jackson/core/jackson-databind/#{jackson_databind_version}/jackson-databind-#{jackson_databind_version}.jar",
"lib/com/fasterxml/jackson/module/jackson-module-afterburner/#{jackson_version}/jackson-module-afterburner-#{jackson_version}.jar",
Expand Down
20 changes: 10 additions & 10 deletions run_all_individual_bench.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@
chruby-exec ruby-2.2.2 -- ruby benchmarking/individual/json-mri-sourced.rb
chruby-exec ruby-2.2.2 -- ruby benchmarking/individual/oj-mri-sourced.rb

chruby-exec jruby-9.2.0.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/json-jr-sourced.rb
chruby-exec jruby-9.4.14.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/json-jr-sourced.rb

chruby-exec jruby-9.2.0.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/string-jr-sourced.rb
chruby-exec jruby-9.2.0.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/str-bd-jr-sourced.rb
chruby-exec jruby-9.4.14.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/string-jr-sourced.rb
chruby-exec jruby-9.4.14.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/str-bd-jr-sourced.rb

chruby-exec jruby-9.2.0.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/symbol-jr-sourced.rb
chruby-exec jruby-9.2.0.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/sym-bd-jr-sourced.rb
chruby-exec jruby-9.4.14.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/symbol-jr-sourced.rb
chruby-exec jruby-9.4.14.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/sym-bd-jr-sourced.rb

chruby-exec jruby-9.2.0.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/raw-jr-sourced.rb
chruby-exec jruby-9.2.0.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/raw-bd-jr-sourced.rb
chruby-exec jruby-9.4.14.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/raw-jr-sourced.rb
chruby-exec jruby-9.4.14.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/raw-bd-jr-sourced.rb

chruby-exec jruby-9.2.0.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/sj-jr-sourced.rb
chruby-exec jruby-9.4.14.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/sj-jr-sourced.rb

chruby-exec ruby-2.2.2 -- ruby benchmarking/individual/json-gen-mri-sourced.rb
chruby-exec ruby-2.2.2 -- ruby benchmarking/individual/oj-gen-mri-sourced.rb

chruby-exec jruby-9.2.0.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/json-gen-jr-sourced.rb
chruby-exec jruby-9.2.0.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/raw-gen-jr-sourced.rb
chruby-exec jruby-9.4.14.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/json-gen-jr-sourced.rb
chruby-exec jruby-9.4.14.0 -- ruby -J-Xmn512m -J-Xms2048m -J-Xmx2048m benchmarking/individual/raw-gen-jr-sourced.rb
1 change: 0 additions & 1 deletion run_jruby_individual_bench.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,3 @@ jruby -J-Xmn1024m -J-Xms4096m -J-Xmx4096m -S ./benchmarking/individual/raw-jr-so
jruby -J-Xmn1024m -J-Xms4096m -J-Xmx4096m -S ./benchmarking/individual/raw-bd-jr-sourced.rb

jruby -J-Xmn1024m -J-Xms4096m -J-Xmx4096m -S ./benchmarking/individual/sj-jr-sourced.rb

36 changes: 21 additions & 15 deletions src/main/java/com/jrjackson/JrJacksonBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import org.jruby.RubySymbol;
import org.jruby.anno.JRubyMethod;
import org.jruby.exceptions.RaiseException;
import org.jruby.ext.stringio.StringIO;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;
Expand Down Expand Up @@ -109,16 +108,26 @@ protected static IRubyObject _sjcparse(ThreadContext context, IRubyObject handle
return sp.deserialize(jp);
}

protected static JsonParser buildParser(ThreadContext ctx, JsonFactory jf, IRubyObject arg) throws IOException {
private static boolean isStringIO(IRubyObject arg) {
return "StringIO".equals(arg.getMetaClass().getName());
}

protected static byte[] extractBytes(ThreadContext ctx, IRubyObject arg) {
if (arg instanceof RubyString) {
return jf.createParser(((RubyString) arg).getByteList().bytes());
} else if (arg instanceof StringIO) {
RubyString content = (RubyString) ((StringIO) arg).string(ctx);
return jf.createParser(content.getByteList().bytes());
} else {
// must be an IO object then
return jf.createParser(((RubyIO) arg).getInStream());
return ((RubyString) arg).getByteList().bytes();
} else if (isStringIO(arg)) {
RubyString content = arg.callMethod(ctx, "string").convertToString();
Comment thread
jsvd marked this conversation as resolved.
return content.getByteList().bytes();
}
return null;
}

protected static JsonParser buildParser(ThreadContext ctx, JsonFactory jf, IRubyObject arg) throws IOException {
byte[] bytes = extractBytes(ctx, arg);
if (bytes != null) {
return jf.createParser(bytes);
}
return jf.createParser(((RubyIO) arg).getInStream());
}

protected static IRubyObject _parse(ThreadContext context, IRubyObject arg, ObjectMapper mapper) throws IOException, RaiseException {
Expand All @@ -128,13 +137,10 @@ protected static IRubyObject _parse(ThreadContext context, IRubyObject arg, Obje
mapper.setDateFormat(simpleFormat);
try {
Object o;
if (arg instanceof RubyString) {
o = mapper.readValue(((RubyString) arg).getByteList().bytes(), Object.class);
} else if (arg instanceof StringIO) {
RubyString content = (RubyString) ((StringIO) arg).string(context);
o = mapper.readValue(content.getByteList().bytes(), Object.class);
byte[] bytes = extractBytes(context, arg);
if (bytes != null) {
o = mapper.readValue(bytes, Object.class);
} else {
// must be an IO object then
o = mapper.readValue(((RubyIO) arg).getInStream(), Object.class);
}
return RubyUtils.rubyObject(ruby, o);
Expand Down
22 changes: 10 additions & 12 deletions src/main/java/com/jrjackson/RubyAnySerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.type.WritableTypeId;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import org.jruby.RubyArray;
import org.jruby.RubyClass;
Expand Down Expand Up @@ -255,22 +257,18 @@ private void serializeKey(IRubyObject key, JsonGenerator jgen, SerializerProvide
}
}

/**
* Default implementation will write type prefix, call regular serialization method (since assumption is that value itself does not need JSON Array or Object start/end markers), and then write type suffix. This should work for most cases; some sub-classes may want to change this behavior.
*
* @param value
* @param jgen
* @param provider
* @param typeSer
* @throws java.io.IOException
* @throws com.fasterxml.jackson.core.JsonGenerationException
*/
// TODO: Remove this method. It is dead code that is never triggered because:
Comment thread
jsvd marked this conversation as resolved.
// 1. JrJacksonBase.generate() calls serialize() directly, bypassing ObjectMapper.writeValue()
// 2. No default typing or @JsonTypeInfo is configured on the ObjectMapper
// Kept for now in case external consumers use the ObjectMapper with polymorphic typing.
@Deprecated(since = "0.5.0", forRemoval = true)
@Override
public void serializeWithType(IRubyObject value, JsonGenerator jgen, SerializerProvider provider, TypeSerializer typeSer)
throws IOException, JsonGenerationException {
typeSer.writeTypePrefixForScalar(value, jgen);
WritableTypeId typeId = typeSer.typeId(value, JsonToken.VALUE_STRING);
typeSer.writeTypePrefix(jgen, typeId);
serialize(value, jgen, provider);
typeSer.writeTypeSuffixForScalar(value, jgen);
typeSer.writeTypeSuffix(jgen, typeId);
}

enum RUBYCLASS {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/jrjackson/RubyJacksonModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ protected SimpleDateFormat initialValue() {
}

private RubyJacksonModule() {
super("JrJacksonStrModule", new Version(1, 2, 28, "0", "com.jrjackson.jruby", "jrjackson"));
super("JrJacksonStrModule", new Version(1, 3, 0, "0", "com.jrjackson.jruby", "jrjackson"));
}

public static ObjectMapper mapperWith(Ruby ruby, RubyKeyConverter nameConverter,
Expand Down
9 changes: 8 additions & 1 deletion src/main/java/com/jrjackson/RubyObjectDeserializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.fasterxml.jackson.core.*;

import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.util.ObjectBuffer;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;

Expand Down Expand Up @@ -90,7 +91,13 @@ public RubyObject deserialize(JsonParser jp, DeserializationContext ctxt)
case END_ARRAY: // invalid
case END_OBJECT: // invalid
default:
throw ctxt.mappingException(Object.class);
throw JsonMappingException.from(
jp,
String.format(
"Unexpected token (%s) when deserializing Ruby object",
jp.currentToken()
)
);
}
}

Expand Down
10 changes: 2 additions & 8 deletions src/test/java/com/jrjackson/RubyAnySerializerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.CompatVersion;
import org.jruby.Ruby;
import org.jruby.RubyHash;
import org.jruby.RubyInstanceConfig;
import org.jruby.ext.bigdecimal.RubyBigDecimal;
import org.jruby.util.ByteList;
import org.junit.Before;
Expand All @@ -27,15 +25,11 @@ public class RubyAnySerializerTest {
public void setUp() throws Exception {
if (setupDone) return;

RubyInstanceConfig config_19 = new RubyInstanceConfig();
config_19.setCompatVersion(CompatVersion.RUBY1_9);
ruby = Ruby.newInstance(config_19);
ruby = Ruby.newInstance();
RubyBigDecimal.createBigDecimal(ruby); // we need to do 'require "bigdecimal"'
// JrubyTimestampExtLibrary.createTimestamp(ruby);
setupDone = true;
}


@Test
public void testSerialize() throws Exception {
RubyHash rh = RubyHash.newHash(ruby);
Expand All @@ -53,4 +47,4 @@ public void testSerialize() throws Exception {
UTF8Encoding.INSTANCE);
assertThat(bl.toString(), is(equalTo("{\"somekey\":123}")));
}
}
}
27 changes: 27 additions & 0 deletions test/jrjackson_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,33 @@ def test_bad_utf
end
end

def test_deserializer_unexpected_token_error_path
require 'java'

runtime = org.jruby.Ruby.getGlobalRuntime
deserializer = Java::ComJrjackson::RubyObjectDeserializer.new
deserializer = deserializer.with(
runtime,
Java::ComJrjackson::RubyStringKeyConverter.new,
Java::ComJrjackson::RubyIntValueConverter.new,
Java::ComJrjackson::RubyFloatValueConverter.new
)

mapper = Java::ComFasterxmlJacksonDatabind::ObjectMapper.new
parser = mapper.factory.create_parser("[]")

parser.next_token # START_ARRAY
parser.next_token # END_ARRAY

context = mapper.deserialization_context

error = assert_raise(Java::ComFasterxmlJacksonDatabind::JsonMappingException) do
deserializer.deserialize(parser, context)
end

assert_match(/Unexpected token \(END_ARRAY\) when deserializing Ruby object/, error.message)
end

def test_can_parse_bignum
expected = 12345678901234567890123456789
json = '{"foo":12345678901234567890123456789}'
Expand Down
Loading