I have a simple Spring Boot/Spring Data Rest test application with a single entity "Contact" and a single CRUDRepository. There is no other code.
When the database is empty, requesting the api+json metadata on /contact works properly:
$ curl -s 'http://localhost:8080/contacts' \
-H 'Accept: application/vnd.api+json'\
-H 'Content-Type: application/hal+json'
...produces:
{
"links" : [ {
"rel" : "self",
"href" : "http://localhost:8080/contacts"
}, {
"rel" : "profile",
"href" : "http://localhost:8080/profile/contacts"
} ],
"content" : [ {
"relTargetType" : "sdr.Contact",
"collectionValue" : true,
"rel" : null,
"value" : [ ]
} ]
}
However, when I put a single contact in the database, the same request produces a massive recursive dump of information:
{
"links" : [ {
"rel" : "self",
"href" : "http://localhost:8080/contacts"
}, {
"rel" : "profile",
"href" : "http://localhost:8080/profile/contacts"
} ],
"content" : [ {
"id" : 2,
"firstName" : "Test",
"lastName" : "Contact",
"embeddeds" : {
"content" : [ ]
},
"propertyAccessor" : {
"bean" : {
"id" : 2,
"firstName" : "Test",
"lastName" : "Contact"
}
},
"persistentEntity" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
"type" : "java.lang.Long",
"modifiers" : 2,
"annotations" : [ ],
"declaredAnnotations" : [ ],
"synthetic" : false,
"declaringClass" : "sdr.Contact",
"enumConstant" : false,
"genericType" : "java.lang.Long",
"annotatedType" : {
"type" : "java.lang.Long",
"annotations" : [ ],
"declaredAnnotations" : [ ]
},
"accessible" : true
},
"association" : false,
"owner" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
"type" : "java.lang.Long",
"modifiers" : 2,
"annotations" : [ ],
"declaredAnnotations" : [ ],
"synthetic" : false,
"declaringClass" : "sdr.Contact",
"enumConstant" : false,
"genericType" : "java.lang.Long",
"annotatedType" : {
"type" : "java.lang.Long",
"annotations" : [ ],
"declaredAnnotations" : [ ]
},
"accessible" : true
},
"association" : false,
"owner" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
"type" : "java.lang.Long",
"modifiers" : 2,
"annotations" : [ ],
"declaredAnnotations" : [ ],
"synthetic" : false,
"declaringClass" : "sdr.Contact",
"enumConstant" : false,
"genericType" : "java.lang.Long",
"annotatedType" : {
"type" : "java.lang.Long",
"annotations" : [ ],
"declaredAnnotations" : [ ]
},
"accessible" : true
},
"association" : false,
"owner" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
"type" : "java.lang.Long",
"modifiers" : 2,
"annotations" : [ ],
"declaredAnnotations" : [ ],
"synthetic" : false,
"declaringClass" : "sdr.Contact",
"enumConstant" : false,
"genericType" : "java.lang.Long",
"annotatedType" : {
"type" : "java.lang.Long",
"annotations" : [ ],
"declaredAnnotations" : [ ]
},
"accessible" : true
},
"association" : false,
"owner" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
"type" : "java.lang.Long",
"modifiers" : 2,
"annotations" : [ ],
"declaredAnnotations" : [ ],
"synthetic" : false,
"declaringClass" : "sdr.Contact",
"enumConstant" : false,
"genericType" : "java.lang.Long",
"annotatedType" : {
"type" : "java.lang.Long",
"annotations" : [ ],
"declaredAnnotations" : [ ]
},
"accessible" : true
},
"association" : false,
"owner" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
"type" : "java.lang.Long",
"modifiers" : 2,
"annotations" : [ ],
"declaredAnnotations" : [ ],
"synthetic" : false,
"declaringClass" : "sdr.Contact",
"enumConstant" : false,
"genericType" : "java.lang.Long",
"annotatedType" : {
"type" : "java.lang.Long",
"annotations" : [ ],
"declaredAnnotations" : [ ]
},
"accessible" : true
},
"association" : false,
"owner" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
"type" : "java.lang.Long",
"modifiers" : 2,
"annotations" : [ ],
"declaredAnnotations" : [ ],
"synthetic" : false,
"declaringClass" : "sdr.Contact",
"enumConstant" : false,
"genericType" : "java.lang.Long",
"annotatedType" : {
"type" : "java.lang.Long",
"annotations" : [ ],
"declaredAnnotations" : [ ]
},
"accessible" : true
},
"association" : false,
"owner" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
"type" : "java.lang.Long",
"modifiers" : 2,
"annotations" : [ ],
"declaredAnnotations" : [ ],
"synthetic" : false,
"declaringClass" : "sdr.Contact",
"enumConstant" : false,
"genericType" : "java.lang.Long",
"annotatedType" : {
"type" : "java.lang.Long",
"annotations" : [ ],
"declaredAnnotations" : [ ]
},
"accessible" : true
},
"association" : false,
"owner" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
"type" : "java.lang.Long",
"modifiers" : 2,
"annotations" : [ ],
"declaredAnnotations" : [ ],
"synthetic" : false,
"declaringClass" : "sdr.Contact",
"enumConstant" : false,
"genericType" : "java.lang.Long",
"annotatedType" : {
"type" : "java.lang.Long",
"annotations" : [ ],
"declaredAnnotations" : [ ]
},
"accessible" : true
},
"association" : false,
"owner" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
"type" : "java.lang.Long",
"modifiers" : 2,
"annotations" : [ ],
"declaredAnnotations" : [ ],
"synthetic" : false,
"declaringClass" : "sdr.Contact",
"enumConstant" : false,
"genericType" : "java.lang.Long",
"annotatedType" : {
"type" : "java.lang.Long",
"annotations" : [ ],
"declaredAnnotations" : [ ]
},
"accessible" : true
},
"association" : false,
"owner" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
"type" : "java.lang.Long",
"modifiers" : 2,
"annotations" : [ ],
"declaredAnnotations" : [ ],
"synthetic" : false,
"declaringClass" : "sdr.Contact",
"enumConstant" : false,
"genericType" : "java.lang.Long",
"annotatedType" : {
"type" : "java.lang.Long",
"annotations" : [ ],
"declaredAnnotations" : [ ]
},
"accessible" : true
},
"association" : false,
"owner" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
"type" : "java.lang.Long",
"modifiers" : 2,
"annotations" : [ ],
"declaredAnnotations" : [ ],
"synthetic" : false,
"declaringClass" : "sdr.Contact",
"enumConstant" : false,
"genericType" : "java.lang.Long",
"annotatedType" : {
"type" : "java.lang.Long",
"annotations" : [ ],
"declaredAnnotations" : [ ]
},
"accessible" : true
},
"association" : false,
"owner" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
"type" : "java.lang.Long",
"modifiers" : 2,
"annotations" : [ ],
"declaredAnnotations" : [ ],
"synthetic" : false,
"declaringClass" : "sdr.Contact",
"enumConstant" : false,
"genericType" : "java.lang.Long",
"annotatedType" : {
"type" : "java.lang.Long",
"annotations" : [ ],
"declaredAnnotations" : [ ]
},
"accessible" : true
},
"association" : false,
"owner" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
"type" : "java.lang.Long",
"modifiers" : 2,
"annotations" : [ ],
"declaredAnnotations" : [ ],
"synthetic" : false,
"declaringClass" : "sdr.Contact",
"enumConstant" : false,
"genericType" : "java.lang.Long",
"annotatedType" : {
"type" : "java.lang.Long",
"annotations" : [ ],
"declaredAnnotations" : [ ]
},
"accessible" : true
},
"association" : false,
"owner" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
"type" : "java.lang.Long",
"modifiers" : 2,
"annotations" : [ ],
"declaredAnnotations" : [ ],
"synthetic" : false,
"declaringClass" : "sdr.Contact",
"enumConstant" : false,
"genericType" : "java.lang.Long",
"annotatedType" : {
"type" : "java.lang.Long",
"annotations" : [ ],
"declaredAnnotations" : [ ]
},
"accessible" : true
},
"association" : false,
"owner" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
"type" : "java.lang.Long",
"modifiers" : 2,
"annotations" : [ ],
"declaredAnnotations" : [ ],
"synthetic" : false,
"declaringClass" : "sdr.Contact",
"enumConstant" : false,
"genericType" : "java.lang.Long",
"annotatedType" : {
"type" : "java.lang.Long",
"annotations" : [ ],
"declaredAnnotations" : [ ]
},
"accessible" : true
},
"association" : false,
"owner" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
"type" : "java.lang.Long",
"modifiers" : 2,
"annotations" : [ ],
"declaredAnnotations" : [ ],
"synthetic" : false,
"declaringClass" : "sdr.Contact",
"enumConstant" : false,
"genericType" : "java.lang.Long",
"annotatedType" : {
"type" : "java.lang.Long",
"annotations" : [ ],
"declaredAnnotations" : [ ]
},
"accessible" : true
},
"association" : false,
"owner" : {
"idProperty" : {
"name" : "id",
"rawType" : "java.lang.Long",
"field" : {
"name" : "id",
***SNIP, THIS GOES ON FOREVER ***
Why is this recursive result returned? Is this expected behavior?
Everything else works normally. There are no JPA relationships or any other complicating factors in the test application. I am able to use the HAL Browser to add and remove records, etc.
I am using Spring Boot 1.3.2 and Spring Data Rest 2.4.2.
Here's the sole entity in the application:
@Entity
public class Contact {
private Long id;
private String firstName;
private String lastName;
public Contact() {
}
@Id
@GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Basic
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
@Basic
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Repository:
@Repository
@RepositoryRestResource
public interface ContactRepository extends CrudRepository<Contact, Long> {
}
That's the entirety of the code in the app.
UPDATE: This appears to be a bug in Spring Data REST. See DATAREST-767 for a test application. Also may be related to DATAREST-733 and DATAREST-734