spring-projects / spring-projects/spring-data-rest
PUT for nested abstract entity has unexpected results [DATAREST-869]
@odrotbohm is already working on this.
Since Dec 31, 2020.
- Dominant language
- Java
- Stars
- 958
- Forks
- 568
- PR merge metrics
- No merged PRs in 30d
Description
Michael S opened DATAREST-869 and commented
There's a problem when updating an abstract type in an entity using PUT. Imagine the following classes including getters/setters and a simple CrudRepository for Owner
@Entity
public class Owner {
@Id
@GeneratedValue
private Integer id;
private String name;
@OneToOne(orphanRemoval = true, cascade = { CascadeType.ALL })
@JoinColumn(name = "pet_id")
private Pet pet;
}
//@formatter:off
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXISTING_PROPERTY,
property = "type"
)
@JsonSubTypes({
@Type(value = Cat.class, name = Cat.TYPE),
@Type(value = Dog.class, name = Dog.TYPE)
})
//@formatter:on
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Pet {
@Id
@GeneratedValue
private Integer id;
private final String type;
}
@Entity
public class Dog extends Pet {
public static final String TYPE = "dog";
private String favoriteToy;
public Dog() {
super(TYPE);
}
}
@Entity
public class Cat extends Pet {
public static final String TYPE = "cat";
private String nickName;
public Cat() {
super(TYPE);
}
}
Creating (i.e. POSTing) an Owner with either Pet type works as expected, however changing the Pet and PUTting gets unexpected results (the type changes, but the value remains null), e.g. (pseudocode):
Owner o = new Owner(new Dog("a stick"));
Owner result = post(o);
assertEquals(o, result); // true, same owner, same pet
o.setPet(new Cat("Lucy"));
Owner result = putToExisting(o);
assertEquals(o, result); // false, cat.nickName is null
As far as I could figure out, this is because the doMerge method in DomainObjectReader doesn't check for different types, but only iterates over the existing (root) entity's properties and merges only their known properties.
I added a quickstart project with an AppTest that illustrates the problem. The easiest - but not really satisfying - workaround I could find was to use a Pet Array on JSON level, this way the value gets skipped in doMerge and just the new value gets used (uncomment the lines in Owner to let the AppTest pass)
Affects: 2.4.4 (Gosling SR4)
Attachments:
- example.zip (10.20 kB)
- example-869.tgz (2.90 kB)
2 votes, 4 watchers
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.