Neo4j - Custom converter for field of type List

巧了我就是萌 提交于 2021-01-06 03:35:14

问题


I am trying to write a custom converter for a nested object so that this object gets saved as string in Neo4j database.

I am using @Convert annotation on my field and passing ImageConverter.class which is my AttributeConverter class.

Everything works fine as expected and I am able to save string representation of Image class in Neo4j db.

However, now instead of single image I want to have List<Image> as my nested field. In this case, putting @Convert(ImageConverter.class) doesn't work.

I see that there is a class called ConverterBasedCollectionConverter which gets used when I have a field of type List<LocalDateTime.

However, I couldn't find any exammples on how to use this class in case of custom converters.

Please can anyone help me with this or if there is any other approach to use custom converter on field of type List.

I am using Neo4j (version 3.4.1) and Spring-data-neo4j (5.0.10.RELEASE) in my application. I am also using OGM.

PS: I am aware that it is advised to store nested objects as separate node establishing a relationship with parent object. However, my use case demands that the object be stored as string property and not as separate node.

Regards,

V


回答1:


It is not so difficult as I assumed it would be.

Given a class (snippet)

@NodeEntity
public class Actor {

  @Id @GeneratedValue
  private Long id;

  @Convert(MyImageListConverter.class)
  public List<MyImage> images = new ArrayList<>();
  // ....
}

with MyImage as simple as can be

public class MyImage {

  public String blob;

  public MyImage(String blob) {
      this.blob = blob;
  }

  public static MyImage of(String value) {
      return new MyImage(value);
  }
}

and a converter

public class MyImageListConverter implements AttributeConverter<List<MyImage>, String[]> {

  @Override
  public String[] toGraphProperty(List<MyImage> value) {
      if (value == null) {
          return null;
      }
      String[] values = new String[(value.size())];
      int i = 0;
      for (MyImage image : value) {
          values[i++] = image.blob;
      }
      return values;
    }

    @Override
    public List<MyImage> toEntityAttribute(String[] values) {
      List<MyImage> images = new ArrayList<>(values.length);
      for (String value : values) {
          images.add(MyImage.of(value));
      }
      return images;
    }
}

will print following debug output on save that I think is what you want:

UNWIND {rows} as row CREATE (n:Actor) SET n=row.props RETURN row.nodeRef as ref, ID(n) as id, {type} as type with params {type=node, rows=[{nodeRef=-1, props={images=[blobb], name=Jeff}}]}

especially the images part.

Test method for this looks like

@Test
public void test() {
    Actor jeff = new Actor("Jeff");
    String blobValue = "blobb";
    jeff.images.add(new MyImage(blobValue));
    session.save(jeff);
    session.clear();
    Actor loadedActor = session.load(Actor.class, jeff.getId());
    assertThat(loadedActor.images.get(0).blob).isEqualTo(blobValue);

}



回答2:


I am came up with a solution to my problem. So, in case you want another solution along with the solution provided by @meistermeier, you can use the below code.

public class ListImageConverter extends ConverterBasedCollectionConverter<Image, String>{

public ListImageConverter() {
    super(List.class, new ImageConverter());
}

@Override
public String[] toGraphProperty(Collection<Image> values) {
    Object[] graphProperties = super.toGraphProperty(values);
    String[] stringArray = Arrays.stream(graphProperties).toArray(String[]::new);
    return stringArray;
}

@Override
public Collection<Image> toEntityAttribute(String[] values) {
    return super.toEntityAttribute(values);
}

}

ImageConverter class just implements AttributeConverter<Image, String> where I serialize and deserialize my Image object to/from json.

I chose to go with this approach because I had Image field in one object and List<Image> in another object. So just by changing @Convert(ListImageConverter.class) to @Convert(ImageConverter.class) I was able to save list as well as single object in Neo4j database.

Note: You can skip overriding toEntityAttribute method if you want. It doesn't add much value. However you have to override toGraphProperty as within Neo4j code it checks for presence of declared method with name toGraphProperty.

Hope this helps someone!

Regards,

V



来源:https://stackoverflow.com/questions/54431684/neo4j-custom-converter-for-field-of-type-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!