mirror of
https://github.com/elastic/logstash.git
synced 2025-04-23 22:27:21 -04:00
correctly handle BigDecimal Rubyfying
BigDecimal fix spec
This commit is contained in:
parent
a1ac7e699f
commit
f3c29faeaf
3 changed files with 236 additions and 0 deletions
|
@ -96,6 +96,14 @@ describe LogStash::Event do
|
|||
e["[foo]"] = nil
|
||||
expect(e.to_hash).to include("foo" => nil)
|
||||
end
|
||||
|
||||
# BigDecinal is now natively converted by JRuby, see https://github.com/elastic/logstash/pull/4838
|
||||
it "should set BigDecimal" do
|
||||
e = LogStash::Event.new()
|
||||
e["[foo]"] = BigDecimal.new(1)
|
||||
expect(e["foo"]).to be_kind_of(BigDecimal)
|
||||
expect(e["foo"]).to eq(BigDecimal.new(1))
|
||||
end
|
||||
end
|
||||
|
||||
context "timestamp" do
|
||||
|
|
|
@ -4,9 +4,11 @@ import com.logstash.ext.JrubyTimestampExtLibrary;
|
|||
import org.jruby.Ruby;
|
||||
import org.jruby.RubyArray;
|
||||
import org.jruby.RubyHash;
|
||||
import org.jruby.ext.bigdecimal.RubyBigDecimal;
|
||||
import org.jruby.javasupport.JavaUtil;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
|
||||
public final class Rubyfier {
|
||||
|
@ -20,6 +22,9 @@ public final class Rubyfier {
|
|||
if (input instanceof Timestamp) return JrubyTimestampExtLibrary.RubyTimestamp.newRubyTimestamp(runtime, (Timestamp)input);
|
||||
if (input instanceof Collection) throw new ClassCastException("unexpected Collection type " + input.getClass());
|
||||
|
||||
// BigDecimal is not currenly handled by JRuby and this is the type Jackson uses for floats
|
||||
if (input instanceof BigDecimal) return new RubyBigDecimal(runtime, runtime.getClass("BigDecimal"), (BigDecimal)input);
|
||||
|
||||
return JavaUtil.convertJavaToUsableRubyObject(runtime, input);
|
||||
}
|
||||
|
||||
|
@ -29,6 +34,9 @@ public final class Rubyfier {
|
|||
if (input instanceof Timestamp) return JrubyTimestampExtLibrary.RubyTimestamp.newRubyTimestamp(runtime, (Timestamp)input);
|
||||
if (input instanceof Collection) throw new ClassCastException("unexpected Collection type " + input.getClass());
|
||||
|
||||
// BigDecimal is not currenly handled by JRuby and this is the type Jackson uses for floats
|
||||
if (input instanceof BigDecimal) return new RubyBigDecimal(runtime, runtime.getClass("BigDecimal"), (BigDecimal)input);
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
package com.logstash;
|
||||
|
||||
import org.jruby.*;
|
||||
import org.jruby.ext.bigdecimal.RubyBigDecimal;
|
||||
import org.jruby.javasupport.JavaUtil;
|
||||
import org.jruby.runtime.builtin.IRubyObject;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class RubyfierTest {
|
||||
|
||||
@Test
|
||||
public void testDeepWithString() {
|
||||
Object result = Rubyfier.deep(Ruby.getGlobalRuntime(), "foo");
|
||||
assertEquals(RubyString.class, result.getClass());
|
||||
assertEquals("foo", result.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepMapWithString()
|
||||
throws Exception
|
||||
{
|
||||
Map data = new HashMap();
|
||||
data.put("foo", "bar");
|
||||
RubyHash rubyHash = ((RubyHash)Rubyfier.deep(Ruby.getGlobalRuntime(), data));
|
||||
|
||||
// Hack to be able to retrieve the original, unconverted Ruby object from Map
|
||||
// it seems the only method providing this is internalGet but it is declared protected.
|
||||
// I know this is bad practice but I think this is practically acceptable.
|
||||
Method internalGet = RubyHash.class.getDeclaredMethod("internalGet", IRubyObject.class);
|
||||
internalGet.setAccessible(true);
|
||||
Object result = internalGet.invoke(rubyHash, JavaUtil.convertJavaToUsableRubyObject(Ruby.getGlobalRuntime(), "foo"));
|
||||
|
||||
assertEquals(RubyString.class, result.getClass());
|
||||
assertEquals("bar", result.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepListWithString()
|
||||
throws Exception
|
||||
{
|
||||
List data = new ArrayList();
|
||||
data.add("foo");
|
||||
|
||||
RubyArray rubyArray = ((RubyArray)Rubyfier.deep(Ruby.getGlobalRuntime(), data));
|
||||
|
||||
// toJavaArray does not convert inner elemenst to Java types \o/
|
||||
assertEquals(RubyString.class, rubyArray.toJavaArray()[0].getClass());
|
||||
assertEquals("foo", rubyArray.toJavaArray()[0].toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepWithInteger() {
|
||||
Object result = Rubyfier.deep(Ruby.getGlobalRuntime(), 1);
|
||||
assertEquals(RubyFixnum.class, result.getClass());
|
||||
assertEquals(1L, ((RubyFixnum)result).getLongValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepMapWithInteger()
|
||||
throws Exception
|
||||
{
|
||||
Map data = new HashMap();
|
||||
data.put("foo", 1);
|
||||
RubyHash rubyHash = ((RubyHash)Rubyfier.deep(Ruby.getGlobalRuntime(), data));
|
||||
|
||||
// Hack to be able to retrieve the original, unconverted Ruby object from Map
|
||||
// it seems the only method providing this is internalGet but it is declared protected.
|
||||
// I know this is bad practice but I think this is practically acceptable.
|
||||
Method internalGet = RubyHash.class.getDeclaredMethod("internalGet", IRubyObject.class);
|
||||
internalGet.setAccessible(true);
|
||||
Object result = internalGet.invoke(rubyHash, JavaUtil.convertJavaToUsableRubyObject(Ruby.getGlobalRuntime(), "foo"));
|
||||
|
||||
assertEquals(RubyFixnum.class, result.getClass());
|
||||
assertEquals(1L, ((RubyFixnum)result).getLongValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepListWithInteger()
|
||||
throws Exception
|
||||
{
|
||||
List data = new ArrayList();
|
||||
data.add(1);
|
||||
|
||||
RubyArray rubyArray = ((RubyArray)Rubyfier.deep(Ruby.getGlobalRuntime(), data));
|
||||
|
||||
// toJavaArray does not convert inner elemenst to Java types \o/
|
||||
assertEquals(RubyFixnum.class, rubyArray.toJavaArray()[0].getClass());
|
||||
assertEquals(1L, ((RubyFixnum)rubyArray.toJavaArray()[0]).getLongValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepWithFloat() {
|
||||
Object result = Rubyfier.deep(Ruby.getGlobalRuntime(), 1.0F);
|
||||
assertEquals(RubyFloat.class, result.getClass());
|
||||
assertEquals(1.0D, ((RubyFloat)result).getDoubleValue(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepMapWithFloat()
|
||||
throws Exception
|
||||
{
|
||||
Map data = new HashMap();
|
||||
data.put("foo", 1.0F);
|
||||
RubyHash rubyHash = ((RubyHash)Rubyfier.deep(Ruby.getGlobalRuntime(), data));
|
||||
|
||||
// Hack to be able to retrieve the original, unconverted Ruby object from Map
|
||||
// it seems the only method providing this is internalGet but it is declared protected.
|
||||
// I know this is bad practice but I think this is practically acceptable.
|
||||
Method internalGet = RubyHash.class.getDeclaredMethod("internalGet", IRubyObject.class);
|
||||
internalGet.setAccessible(true);
|
||||
Object result = internalGet.invoke(rubyHash, JavaUtil.convertJavaToUsableRubyObject(Ruby.getGlobalRuntime(), "foo"));
|
||||
|
||||
assertEquals(RubyFloat.class, result.getClass());
|
||||
assertEquals(1.0D, ((RubyFloat)result).getDoubleValue(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepListWithFloat()
|
||||
throws Exception
|
||||
{
|
||||
List data = new ArrayList();
|
||||
data.add(1.0F);
|
||||
|
||||
RubyArray rubyArray = ((RubyArray)Rubyfier.deep(Ruby.getGlobalRuntime(), data));
|
||||
|
||||
// toJavaArray does not convert inner elemenst to Java types \o/
|
||||
assertEquals(RubyFloat.class, rubyArray.toJavaArray()[0].getClass());
|
||||
assertEquals(1.0D, ((RubyFloat)rubyArray.toJavaArray()[0]).getDoubleValue(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepWithDouble() {
|
||||
Object result = Rubyfier.deep(Ruby.getGlobalRuntime(), 1.0D);
|
||||
assertEquals(RubyFloat.class, result.getClass());
|
||||
assertEquals(1.0D, ((RubyFloat)result).getDoubleValue(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepMapWithDouble()
|
||||
throws Exception
|
||||
{
|
||||
Map data = new HashMap();
|
||||
data.put("foo", 1.0D);
|
||||
RubyHash rubyHash = ((RubyHash)Rubyfier.deep(Ruby.getGlobalRuntime(), data));
|
||||
|
||||
// Hack to be able to retrieve the original, unconverted Ruby object from Map
|
||||
// it seems the only method providing this is internalGet but it is declared protected.
|
||||
// I know this is bad practice but I think this is practically acceptable.
|
||||
Method internalGet = RubyHash.class.getDeclaredMethod("internalGet", IRubyObject.class);
|
||||
internalGet.setAccessible(true);
|
||||
Object result = internalGet.invoke(rubyHash, JavaUtil.convertJavaToUsableRubyObject(Ruby.getGlobalRuntime(), "foo"));
|
||||
|
||||
assertEquals(RubyFloat.class, result.getClass());
|
||||
assertEquals(1.0D, ((RubyFloat)result).getDoubleValue(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepListWithDouble()
|
||||
throws Exception
|
||||
{
|
||||
List data = new ArrayList();
|
||||
data.add(1.0D);
|
||||
|
||||
RubyArray rubyArray = ((RubyArray)Rubyfier.deep(Ruby.getGlobalRuntime(), data));
|
||||
|
||||
// toJavaArray does not convert inner elemenst to Java types \o/
|
||||
assertEquals(RubyFloat.class, rubyArray.toJavaArray()[0].getClass());
|
||||
assertEquals(1.0D, ((RubyFloat)rubyArray.toJavaArray()[0]).getDoubleValue(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepWithBigDecimal() {
|
||||
Object result = Rubyfier.deep(Ruby.getGlobalRuntime(), new BigDecimal(1));
|
||||
assertEquals(RubyBigDecimal.class, result.getClass());
|
||||
assertEquals(1.0D, ((RubyBigDecimal)result).getDoubleValue(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepMapWithBigDecimal()
|
||||
throws Exception
|
||||
{
|
||||
Map data = new HashMap();
|
||||
data.put("foo", new BigDecimal(1));
|
||||
|
||||
RubyHash rubyHash = ((RubyHash)Rubyfier.deep(Ruby.getGlobalRuntime(), data));
|
||||
|
||||
// Hack to be able to retrieve the original, unconverted Ruby object from Map
|
||||
// it seems the only method providing this is internalGet but it is declared protected.
|
||||
// I know this is bad practice but I think this is practically acceptable.
|
||||
Method internalGet = RubyHash.class.getDeclaredMethod("internalGet", IRubyObject.class);
|
||||
internalGet.setAccessible(true);
|
||||
Object result = internalGet.invoke(rubyHash, JavaUtil.convertJavaToUsableRubyObject(Ruby.getGlobalRuntime(), "foo"));
|
||||
|
||||
assertEquals(RubyBigDecimal.class, result.getClass());
|
||||
assertEquals(1.0D, ((RubyBigDecimal)result).getDoubleValue(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepListWithBigDecimal()
|
||||
throws Exception
|
||||
{
|
||||
List data = new ArrayList();
|
||||
data.add(new BigDecimal(1));
|
||||
|
||||
RubyArray rubyArray = ((RubyArray)Rubyfier.deep(Ruby.getGlobalRuntime(), data));
|
||||
|
||||
// toJavaArray does not convert inner elemenst to Java types \o/
|
||||
assertEquals(RubyBigDecimal.class, rubyArray.toJavaArray()[0].getClass());
|
||||
assertEquals(1.0D, ((RubyBigDecimal)rubyArray.toJavaArray()[0]).getDoubleValue(), 0);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue