Java – unable to get JPA entity ID in JSON output
We are trying to use the POC of spring data JPA and spring data rest
We are using a simple entity that extends abstractpersistent (which is a spring data JPA class) http://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/domain/AbstractPersistable.html ).
This is the source code of this one:
@MappedSuperclass public abstract class AbstractPersistable<PK extends Serializable> implements Persistable<PK> { private static final long serialVersionUID = -5554308939380869754L; @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "ID") private PK id; /* * (non-Javadoc) * * @see org.springframework.data.domain.Persistable#getId() */ public PK getId() { return id; } /** * Sets the id of the entity. * * @param id the id to set */ protected void setId(final PK id) { this.id = id; } /* * (non-Javadoc) * * @see org.springframework.data.domain.Persistable#isNew() */ public boolean isNew() { return null == getId(); } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { return String.format("Entity of type %s with id: %s",this.getClass().getName(),getId()); } /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (null == obj) { return false; } if (this == obj) { return true; } if (!getClass().equals(obj.getClass())) { return false; } AbstractPersistable<?> that = (AbstractPersistable<?>) obj; return null == this.getId() ? false : this.getId().equals(that.getId()); } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int hashCode = 17; hashCode += null == getId() ? 0 : getId().hashCode() * 31; return hashCode; } }
And our entities:
@Entity @Table(name = "TEST_ENTITY") public class TestEntity extends AbstractPersistable<Long> { @Column(name = "TITLE",nullable = false,length = 100) private String title; @Column(name = "DESCRIPTION",length = 500) private String description; @ManyToOne(fetch = FetchType.LAZY,optional = false) @JoinColumn(name = "GLOBAL_DATATYPE_ID",referencedColumnName = "ID",updatable = false) private globalDataType dataType; @Enumerated(EnumType.STRING) @Column(name = "VALUE_TYPE",length = 30) private ValueType valueType; @Enumerated(EnumType.STRING) @Column(name = "ATTRIBUTE_TYPE",length = 30) private AttributeType attributeType; @Column(name = "FE_DISPLAY") @Convert(converter=BooleanTFConverter.class) private Boolean feDisplay; {... getter setter equals hashcode toString ...} }
Then the service (using spring data rest):
@RepositoryRestResource(path = "test") public interface TestEntityRepository extends JpaRepository<TestEntity,Long> { }
We use spring to launch and run the application. The output on chrome (URL: http: / / localhost: 8080 / test) is JSON Hal data (ID!!!):
{ "_links" : { "self" : { "href" : "http://localhost:8080/test{?page,size,sort}","templated" : true } },"_embedded" : { "testEntities" : [ { "title" : "Test","description" : "TEST","valueType" : "SINGLE","attributeType" : "ATTRIBUTE","feDisplay" : true,"new" : false,"_links" : { "self" : { "href" : "http://localhost:8080/test/1" },"dataType" : { "href" : "http://localhost:8080/test/1/dataType" } } } ] },"page" : { "size" : 20,"totalElements" : 1,"totalPages" : 1,"number" : 0 } }
The other thing is when we're in testentity( http://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/domain/AbstractAuditable.html )When abstractauditable is used on, it works. We get the field value from abstractauditable, but we still don't get the id
@Entity @Table(name = "TEST_ENTITY") public class TestEntity extends AbstractAuditable<User,Long> { ... } @MappedSuperclass public abstract class AbstractAuditable<U,PK extends Serializable> extends AbstractPersistable<PK> implements Auditable<U,PK> { private static final long serialVersionUID = 141481953116476081L; @ManyToOne(fetch = FetchType.LAZY,optional = false) @JoinColumn(name = "CREATED_BY",updatable = false) private U createdBy; @Temporal(TemporalType.TIMESTAMP) @Column(name = "CREATED_DATE") private Date createdDate; @ManyToOne(fetch = FetchType.LAZY,optional = false) @JoinColumn(name = "LAST_MODIFIED_BY",updatable = false) private U lastModifiedBy; @Temporal(TemporalType.TIMESTAMP) @Column(name = "LAST_MODIFIED_DATE") private Date lastModifiedDate; /* * (non-Javadoc) * * @see org.springframework.data.domain.Auditable#getCreatedBy() */ public U getCreatedBy() { return createdBy; } /* * (non-Javadoc) * * @see * org.springframework.data.domain.Auditable#setCreatedBy(java.lang.Object) */ public void setCreatedBy(final U createdBy) { this.createdBy = createdBy; } /* * (non-Javadoc) * * @see org.springframework.data.domain.Auditable#getCreatedDate() */ public DateTime getCreatedDate() { return null == createdDate ? null : new DateTime(createdDate); } /* * (non-Javadoc) * * @see * org.springframework.data.domain.Auditable#setCreatedDate(org.joda.time * .DateTime) */ public void setCreatedDate(final DateTime createdDate) { this.createdDate = null == createdDate ? null : createdDate.toDate(); } /* * (non-Javadoc) * * @see org.springframework.data.domain.Auditable#getLastModifiedBy() */ public U getLastModifiedBy() { return lastModifiedBy; } /* * (non-Javadoc) * * @see * org.springframework.data.domain.Auditable#setLastModifiedBy(java.lang * .Object) */ public void setLastModifiedBy(final U lastModifiedBy) { this.lastModifiedBy = lastModifiedBy; } /* * (non-Javadoc) * * @see org.springframework.data.domain.Auditable#getLastModifiedDate() */ public DateTime getLastModifiedDate() { return null == lastModifiedDate ? null : new DateTime(lastModifiedDate); } /* * (non-Javadoc) * * @see * org.springframework.data.domain.Auditable#setLastModifiedDate(org.joda * .time.DateTime) */ public void setLastModifiedDate(final DateTime lastModifiedDate) { this.lastModifiedDate = null == lastModifiedDate ? null : lastModifiedDate.toDate(); } }
JSON Hal results:
{ "_links" : { "self" : { "href" : "http://localhost:8080/test{?page,"_embedded" : { "testEntities" : [ { "createdBy" : { "username" : "xxx.admin" },"createdDate" : { "year" : 2014,"era" : 1,"dayOfYear" : 282,"dayOfWeek" : 4,"dayOfMonth" : 9,"weekOfWeekyear" : 41,"monthOfYear" : 10,"yearOfEra" : 2014,"yearOfCentury" : 14,"centuryOfEra" : 20,"weekyear" : 2014,"millisOfSecond" : 0,"millisOfDay" : 65724000,"secondOfMinute" : 24,"secondOfDay" : 65724,"minuteOfHour" : 15,"minuteOfDay" : 1095,"hourOfDay" : 18,"chronology" : { "zone" : { "fixed" : false,"uncachedZone" : { "cachable" : true,"fixed" : false,"id" : "Europe/London" },"id" : "Europe/London" } },"zone" : { "fixed" : false,"uncachedZone" : { "cachable" : true,"id" : "Europe/London" },"id" : "Europe/London" },"millis" : 1412874924000,"afterNow" : false,"beforeNow" : true,"equalNow" : false },"lastModifiedBy" : null,"lastModifiedDate" : { "year" : 2014,"millisOfDay" : 65731000,"secondOfMinute" : 31,"secondOfDay" : 65731,"millis" : 1412874931000,"title" : "Test","number" : 0 } }
Editing: Solutions
Add custom repositoryrestmvcconfiguration
@Configuration public class MyRepositoryRestMvcConfiguration extends RepositoryRestMvcConfiguration { protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { config.exposeIdsFor(TestEntity.class); } }
Then change @ import in your application Java configuration class
Before:
@Configuration @EnableTransactionManagement @Import(RepositoryRestMvcConfiguration.class) @EnableJpaRepositories(basePackages="uk.co.xxx.marketplace.data.repository") @PropertySources({@PropertySource("classpath:hibernate.properties"),@PropertySource("classpath:persistence.properties")}) @ComponentScan(value = "uk.co.xxx.marketplace.data") @EnableAutoConfiguration public class Application { ... }
actual:
@Configuration @EnableTransactionManagement @Import(MyRepositoryRestMvcConfiguration.class) @EnableJpaRepositories(basePackages="uk.co.xxx.marketplace.data.repository") @PropertySources({@PropertySource("classpath:hibernate.properties"),@PropertySource("classpath:persistence.properties")}) @ComponentScan(value = "uk.co.xxx.marketplace.data") @EnableAutoConfiguration public class Application { ... }
Solution
You can inherit the class repositoryrestconfiguration (or repositoryrestmvcconfiguration, if spring MVC is used), and call the method exposeidsfor () with the domain class you want to expose the ID