Skip to content

Commit

Permalink
Support for arbitrary java objects in procedures
Browse files Browse the repository at this point in the history
This is not behavior we want to support but apparently we had been
careless and not sanitized inputs properly and now this is in heavy use.
  • Loading branch information
pontusmelke committed Oct 15, 2017
1 parent a82e9e5 commit b783357
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,12 @@ public void writeByteArray( byte[] value ) throws RuntimeException
writeValue( value );
}

@Override
public void writeJavaObject( Object object )
{
writeValue( object );
}

private interface Writer
{
void write( Object value );
Expand Down
39 changes: 36 additions & 3 deletions community/kernel/src/main/java/org/neo4j/helpers/ValueUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
package org.neo4j.helpers;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
Expand All @@ -37,6 +36,7 @@
import org.neo4j.graphdb.spatial.Point;
import org.neo4j.helpers.collection.Iterables;
import org.neo4j.values.AnyValue;
import org.neo4j.values.AnyValueWriter;
import org.neo4j.values.storable.NumberValue;
import org.neo4j.values.storable.TextValue;
import org.neo4j.values.storable.Values;
Expand Down Expand Up @@ -129,8 +129,7 @@ else if ( object instanceof Object[] )
}
else
{
throw new IllegalArgumentException(
String.format( "Cannot convert %s to AnyValue", object.getClass().getName() ) );
return new JavaObjectAnyValue( object );
}
}
}
Expand Down Expand Up @@ -293,4 +292,38 @@ public static EdgeValue fromRelationshipProxy( Relationship relationship )
{
return new RelationshipProxyWrappingEdgeValue( relationship );
}

public static final class JavaObjectAnyValue extends AnyValue
{
private final Object object;
//The object is null checked before calling constructor
private JavaObjectAnyValue( Object object )
{
assert object != null;
this.object = object;
}

public Object asObject()
{
return object;
}

@Override
protected boolean eq( Object other )
{
return other != null && other.equals( object );
}

@Override
protected int computeHash()
{
return object.hashCode();
}

@Override
public <E extends Exception> void writeTo( AnyValueWriter<E> writer ) throws E
{
writer.writeJavaObject( object );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,9 @@ default void writeVirtualEdgeHack( Object relationship )
{
// do nothing, this is an ugly hack.
}

default void writeJavaObject( Object object )
{
// do nothing, this is an ugly hack.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,22 @@ class ProcedureCallSupportAcceptanceTest extends ProcedureCallAcceptanceTest {
"prop"
)
}


//NOTE this is unwanted behaviour, however since we were careless about sanitizing inputs (https://xkcd.com/327/)
//we are stuck with this behavior until 4.0, consider it extremely deprecated and remove as soon as possible.
test("Support passing arbitrary object in and out of a procedure") {
// Given
registerDummyInOutProcedure(Neo4jTypes.NTAny)
class Arbitrary {
val foo = 42
}
val value = new Arbitrary

// When
val result = graph.execute("CALL my.first.proc({p})", map("p",value))

// Then
result.next().get("out0") should equal(value)
}
}

0 comments on commit b783357

Please sign in to comment.