In other words, the common Jackson markup is not enough for serializing the same entity for using as the REST request response to the Angular frontend and to pass the object to Elasticsearch via the Jest client. Say, I have an image in the Entity as a byte array, and I'd like it to be stored to DB and be passed to the frontend, but don't like it being indexed by Elasticsearch to reduce the costs or quotas.
Now I have to use Jackson's JsonView to markup the fields to use for the Spring Data Elasticsearch's ObjectMapper:
@Entity
@Table(name = "good")
@org.springframework.data.elasticsearch.annotations.Document(indexName = "good", shards = 1, replicas = 0, refreshInterval = "-1")
public class Good implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
@SequenceGenerator(name = "sequenceGenerator")
@org.springframework.data.elasticsearch.annotations.Field(type = FieldType.Keyword)
@JsonView(Views.Elasticsearch.class)
private Long id;
@NotNull
@Column(name = "short_name", nullable = false)
@JsonView(Views.Elasticsearch.class)
@Field(store = true, index = true, type=FieldType.Text)
private String shortName;
@NotNull
@Column(name = "description", nullable = false)
@JsonView(Views.Elasticsearch.class)
@Field(store = true, index = true, type=FieldType.Text)
private String description;
@Lob
@Column(name = "image", nullable = false)
@JsonView(Views.Rest.class)
private byte[] image;
@Column(name = "image_content_type", nullable = false)
@JsonView(Views.Rest.class)
private String imageContentType;
@NotNull
@Column(name = "price", nullable = false)
@JsonView(Views.Elasticsearch.class)
@Field(store = true, index = true, type=FieldType.Integer)
private Integer price;
...
I have a clss for Views
:
public class Views {
public static class Rest{}
public static class Elasticsearch{}
}
And the ObjectMapper set up in the corresponding Bean:
@Override
public String mapToString(Object object) throws IOException {
log.trace("Object to convert to JSON : {}",object);
log.trace("Converting to json for elasticsearch >>> {}",objectMapper.writer().withView(Views.Elasticsearch.class).writeValueAsString(object));
//log.trace("Converting to json for elasticsearch >>> {}",objectMapper.writeValueAsString(object));
return objectMapper.writerWithView(Views.Elasticsearch.class).writeValueAsString(object);
//return objectMapper.writeValueAsString(object);
}
So, I have to markup all the fields except the ignored to Elasticsearch with @JsonView(Views.Elasticsearch.class)
and this is the error prone. Also, this field still requires @Field
usage if I like to pass some parameters there like store
or value type. When I have @JsonView(Views.Elasticsearch.class)
, but don't have @Field
on some, the fields are created in the index on a fly, that allows them to search, but not in desired way.
The latest is the reason why if I just leave @Field there and don't place it over fields I don't want to index into Elasticsearch, the initial index indeed ignores them, but later requests pass the undesired field when the entity is serialized exactly the same way as it is done for the REST. And the index property is created on a fly, making resources being spent for the large binary object indexing. So it looks like @Field
is used for the initial index creation on the startup, but are not configured to be used with ObjectMapper of the Spring Data Elasticsearch.
So, I'd like to make this ObjectMapper take only fields with @Field
above them into account, i.e serialize the fields marked with @Field
only and use no @JsonView
staff. How can I configure it?
These are known problems when using the Jackson Object Mapper in Spring Data Elasticsearch (which als is the default) and this is one of the reasons, why in Spring Data Elasticsearch as of version 3.2 (which currently is in RC2 and will be available as 3.2.0.GA in mid-september), there is a different mapper available, the ElasticsearchEntityMapper
.
This mapper still has to be setup explicitly, the reference documentation of 3.2.0.RC2 shows how to do this. Using this mapper the Jackson annotations do not influence the data stored in and read from Elasticsearch. And you can use the org.springframework.data.annotation.Transient
annotation on a field to not have it stored in Elasticsearch.
The @Field
annotation is used to setup the initial Elasticsearch mapping, properties not having this annotation are automatically mapped by Elasticsearch when they are inserted.