diff --git a/lib/logstash/java_integration.rb b/lib/logstash/java_integration.rb index ef9c22a29..cacbf1712 100644 --- a/lib/logstash/java_integration.rb +++ b/lib/logstash/java_integration.rb @@ -24,24 +24,39 @@ class Hash end end +# map_mixin to patch LinkedHashMap and HashMap. it must be done directly on the classes, +# using a module mixin does not work, and injecting in the Map interface does not work either +# but injecting in the class works. -# this is a temporary fix to solve a bug in JRuby where classes implementing the Map interface, like LinkedHashMap -# have a bug in the has_key? method that is implemented in the Enumerable module that is somehow mixed in the Map interface. -# this bug makes has_key? (and all its aliases) return false for a key that has a nil value. -# Only LinkedHashMap is patched here because patching the Map interface is not working. -# TODO find proper fix, and submit upstream -# releavant JRuby files: -# https://github.com/jruby/jruby/blob/master/core/src/main/ruby/jruby/java/java_ext/java.util.rb -# https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/java/proxies/MapJavaProxy.java -class Java::JavaUtil::LinkedHashMap +map_mixin = lambda do + # this is a temporary fix to solve a bug in JRuby where classes implementing the Map interface, like LinkedHashMap + # have a bug in the has_key? method that is implemented in the Enumerable module that is somehow mixed in the Map interface. + # this bug makes has_key? (and all its aliases) return false for a key that has a nil value. + # Only LinkedHashMap is patched here because patching the Map interface is not working. + # TODO find proper fix, and submit upstream + # releavant JRuby files: + # https://github.com/jruby/jruby/blob/master/core/src/main/ruby/jruby/java/java_ext/java.util.rb + # https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/java/proxies/MapJavaProxy.java def has_key?(key) self.containsKey(key) end alias_method :include?, :has_key? alias_method :member?, :has_key? alias_method :key?, :has_key? + + # Java 8 Map implements a merge method with a different signature from + # the Ruby Hash#merge. see https://github.com/jruby/jruby/issues/1249 + # this can be removed when fixed upstream + if ENV_JAVA['java.specification.version'] >= '1.8' + def merge(other) + dup.merge!(other) + end + end end +Java::JavaUtil::LinkedHashMap.module_exec(&map_mixin) +Java::JavaUtil::HashMap.module_exec(&map_mixin) + module java::util::Map # have Map objects like LinkedHashMap objects report is_a?(Array) == true def is_a?(clazz) diff --git a/spec/lib/logstash/java_integration_spec.rb b/spec/lib/logstash/java_integration_spec.rb index 19c4f0d75..0d4219a8e 100644 --- a/spec/lib/logstash/java_integration_spec.rb +++ b/spec/lib/logstash/java_integration_spec.rb @@ -50,6 +50,35 @@ describe "Java integration" do end end + context "Java::JavaUtil::Map" do + # this is to test the Java 8 Map interface change for the merge method + + let(:merger){{:a => 1, :b => 2}} + let(:mergee){{:b => 3, :c => 4}} + + shared_examples "map merge" do + it "should support merging" do + expect(subject.merge(mergee)).to eq({:a => 1, :b => 3, :c => 4}) + end + + it "should return a new hash and not change original hash" do + expect{subject.merge(mergee)}.to_not change{subject} + end + end + + context "with Java::JavaUtil::LinkedHashMap" do + it_behaves_like "map merge" do + subject{Java::JavaUtil::LinkedHashMap.new(merger)} + end + end + + context "with Java::JavaUtil::HashMap" do + it_behaves_like "map merge" do + subject{Java::JavaUtil::HashMap.new(merger)} + end + end + end + context "Java::JavaUtil::Collection" do subject{Java::JavaUtil::ArrayList.new(initial_array)}