I'm using Spring Boot with Spring Data and H2 in-memory db and wanted to try using Value Objects instead of Strings everywhere and I found this neat library: AutoValue to create Value Objects. So here is my entity:
@Entity
@Access(AccessType.FIELD) // so I can avoid using setters for fields that won't change
class Address {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long addressId;
@Embedded private State state;
@Embedded private ZipCode zipCode;
@Embedded private City city;
@Embedded private Street street;
// many customers might live at the same address
@OneToMany(mappedBy = "address")
private final Set<Customer> customers = new HashSet<>();
// jpa requirement
public Address() {
}
Address(State state, ZipCode zipCode, City city, Street street) {
this.state = state;
this.zipCode = zipCode;
this.city = city;
this.street = street;
}
public Long getAddressId() {
return addressId;
}
public State getState() {
return state;
}
public ZipCode getZipCode() {
return zipCode;
}
public City getCity() {
return city;
}
public Street getStreet() {
return street;
}
public Set<Customer> getCustomers() {
return customers;
}
}
And here is one of the Value Objects (they are all similiar thanks to AutoValue):
@AutoValue
abstract class State {
static State create(String stateName) {
return new AutoValue_State(stateName);
}
abstract String stateName();
}
And when I check my database there are no Columns for Object Values:
How can I fix that?
EDIT1: Here is AddressTest confirming that AutoValue actually creates fields and works ok:
public class AddressTest {
private static final String ANY_STATE = "ANY STATE";
private static final String ANY_ZIP_CODE = "ANY ZIP CODE";
private static final String ANY_CITY = "ANY CITY";
private static final String ANY_STREET = "ANY STREET";
@Test
public void shouldConstructValidAddress() {
// given
State anyState = State.create(ANY_STATE);
ZipCode anyZipCode = ZipCode.create(ANY_ZIP_CODE);
City anyCity = City.create(ANY_CITY);
Street anyStreet = Street.create(ANY_STREET);
// when
Address address = new Address(State.create(ANY_STATE), ZipCode.create(ANY_ZIP_CODE),
City.create(ANY_CITY), Street.create(ANY_STREET));
// then
assertThat(address.getState()).isEqualTo(anyState);
assertThat(address.getZipCode()).isEqualTo(anyZipCode);
assertThat(address.getCity()).isEqualTo(anyCity);
assertThat(address.getStreet()).isEqualTo(anyStreet);
}
EDIT 2: State as value object:
final class State {
private final String stateName;
State(String stateName) {
this.stateName = stateName;
}
public String getStateName() {
return stateName;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
State state = (State) o;
return stateName != null ? stateName.equals(state.stateName) : state.stateName == null;
}
@Override
public int hashCode() {
return stateName != null ? stateName.hashCode() : 0;
}
@Override
public String toString() {
return "State{" +
"stateName='" + stateName + '\'' +
'}';
}
}