Can an AutoValue class do a negative check similar to how it checks for Missing required properties?
Maybe it can support validation by annotations?
#AutoValue
#JsonSerialize(as = ExampleRequest.class)
#JsonDeserialize(builder = ExampleRequest.Builder.class)
public abstract class ExampleRequest {
#JsonProperty("name")
public abstract String name();
#NegativeCheck // is there something available ?
#JsonProperty("version")
public abstract long version();
public static ExampleRequest.Builder builder() {
return Builder.builder();
}
#AutoValue.Builder
#JsonIgnoreProperties(ignoreUnknown = true)
public abstract static class Builder {
#JsonCreator
public static ExampleRequest.Builder builder() {
return new AutoValue_ExampleRequest.Builder();
}
#JsonProperty("name")
public abstract ExampleRequest.Builder name(String name);
#JsonProperty("version")
public abstract ExampleRequest.Builder version(long version);
public abstract ExampleRequest build();
}
}
I can solve it like below
but I was wondering if there is support for some built-in validation using tags so I don't have to write custom validation.
#AutoValue
#JsonSerialize(as = ExampleRequest.class)
#JsonDeserialize(builder = ExampleRequest.Builder.class)
public abstract class ExampleRequest {
#JsonProperty("name")
public abstract String name();
#JsonProperty("version")
public abstract long version();
public static ExampleRequest.Builder builder() {
return Builder.builder();
}
#AutoValue.Builder
#JsonIgnoreProperties(ignoreUnknown = true)
public abstract static class Builder {
#JsonCreator
public static ExampleRequest.Builder builder() {
return new AutoValue_ExampleRequest.Builder();
}
#JsonProperty("name")
public abstract ExampleRequest.Builder name(String name);
#JsonProperty("version")
public abstract ExampleRequest.Builder version(long version);
abstract ExampleRequest autoBuild();
public ExampleRequest build() {
ExampleRequest request = autoBuild();
validateParameterVersion(request.version());
return request;
}
private void validateParameterVersion(long version) {
if (version < 0) {
throw new IllegalStateException("version cannot be negative");
}
}
}
}
Related
I have folowed this way to use polymorphic dto in a spring controller
https://bwgjoseph.com/polymorphic-dto-using-java-record-with-jackson
#JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION, defaultImpl = HomeAddressDto.class)
#JsonSubTypes({
#Type(HomeAddressDto.class),
#Type(OfficeAddressDto.class)
})
public interface Address {
}
public record HomeAddressDto(String street, String postalCode, String unit) implements Address {}
public record OfficeAddressDto(String building, String street, String postalCode, String unit) implements Address {}
That work well but in the controller
#RestController
#RequestMapping("/deduction/addresses")
public class DeductionAddressController {
#PostMapping()
public Address create(#RequestBody Address address) {
if (address instanceof HomeAddressDto) {
System.out.println("home");
}
if (address instanceof OfficeAddressDto) {
System.out.println("office");
}
return address;
}
}
instanceof is used, is there a way to avoid that?
You could create a new service with similar polymorphism, for example
public class DeductionAddressController {
#Autowired
private AddressService addressService;
#PostMapping()
public Address create(#RequestBody Address address) {
addressService.processAddress(address);
return address;
}
}
where AddressService looks like
#Service
public class AddressServiceImpl implements AddressService {
#Override
public void processAddress(HomeAddressDto homeAddress) {
System.out.println("home");
// process HomeAddressDto...
}
#Override
public void processAddress(OfficeAddressDto homeAddress) {
System.out.println("office");
// process OfficeAddressDto...
}
}
I think this might be what you're looking for.
Abstract (Parent) Class:
//I'm assuming this discriminator works
#JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION, defaultImpl = HomeAddressDto.class)
#JsonSubTypes({
#Type(HomeAddressDto.class),
#Type(OfficeAddressDto.class)
})
public abstract class Address {
public enum AddressType {
HOME("home"), OFFICE("office");
// set the rest up
}
public abstract AddressType getType();
}
Home Address Class:
public record HomeAddressDto(String street, String postalCode, String unit) extends Address {
#Overrides
public AddressType getType(){
return AddressType.HOME;
}
}
Office Address Class:
public record OfficeAddressDto(String building, String street, String postalCode, String unit) extends Address {
#Overrides
public AddressType getType(){
return AddressType.OFFICE;
}
}
CONTROLLER:
#RestController
#RequestMapping("/deduction/addresses")
public class DeductionAddressController {
#PostMapping()
public Address create(#RequestBody Address address) {
Log.info(address.getType());
...
...
return address;
}
}
I'd like to solve such problem. I have some abstract class and a concrete class with setters that return the instance of that class:
#MappedSuperclass
public abstract class BaseEntity implements Serializable {
private Integer id;
public Integer getId() {
return id;
}
public BaseEntity setId(Integer id) {
this.id = id;
return this;
}
}
next abstract:
#MappedSuperclass
public abstract class NamedEntity extends BaseEntity {
private String name;
public String getName() {
return name;
}
public NamedEntity setName(String name) {
this.name = name;
return this;
}
}
and finally a concrete class:
#Entity
public class Person extends NamedEntity {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
I'd like to use this kind of builder but in current setup it's not working due to different return types of parent setters
public Person build() {
Person person = new Person()
.setId(1); //return BaseEntity instead of Person
.setName("name") //returns NamedEntity instead of Person
.setAddress("foo"); //return Person!
return person;
}
of course ther's a workaround with overriden setters but.... can it be done other way using generics?
#Override
public Person setId(Integer id) {
super.setId(id);
return this;
}
#Override
public Person setName(String name) {
super.setName(name);
return this;
}
Thanks for all the sugestions
I know the builder pattern, but in this particular case is the same workaround as overriding the methods setId and setName
The point here is:
it is possible that setId method will return the instance of child class the method is called from
let's say I'd like to put a complex object to my builder (why not?):
public class Person extends NamedEntity {
private String address;
... getters/setters
public Builder builder() {
return new Builder();
}
public final static class Builder {
private final Person person;
private Long id;
private String name;
private String address;
private Builder() {
this.person = new Person();
}
public Builder withId(Long id) {
person.setId(id);
return this;
}
..... other setters
public Builder withDto(PersonDTO dto) {
person
.setId(dto.getId())
.setName(dto.getName())
.setAddress(dto.getAddress()
}
public Person build() {
return person;
}
}
}
as you may guess the person.setId returns instance of BaseEntity
You can use the same trick as enums (Enum), a generic type parameter for the child class.
#MappedSuperclass
public abstract class BaseEntity<E extends BaseEntity<E>> implements Serializable {
private Integer id;
public Integer getId() {
return id;
}
protected final E getThis() {
return this;
}
public E setId(Integer id) {
this.id = id;
return getThis();
}
}
#MappedSuperclass
public abstract class NamedEntity<E extends NamedEntity<E>> extends BaseEntity<E> {
private String name;
public String getName() {
return name;
}
public E setName(String name) {
this.name = name;
return getThis();
}
}
For child classes of Person you need not continue with this pattern.
#Entity
public class Person extends NamedEntity<Person> {
private String address;
public String getAddress() {
return address;
}
public Person setAddress(String address) {
this.address = address;
return this;
}
}
Now you can do_
Person einstein = new Person()
.setId(76)
.setName("Albert")
.setAddress("Princeton, New Jersey");
The alternative is a Builder pattern, however it has the same inheritance problem, and you might end up with *.Builder classes inheriting from parent Builder classes.
I would even say it is not worth this boiler plate code, just for a fluent API (chained calls). The criteria API for instance does hardly need using created objects, and the passed values for the setters must come from some code too.
Also setters implies the classes are mutable. It would be much nicer if most fields were immutable. With entity classes unrealistic, but setters are an ugly initialisation. When possible use constructors/builders without setters.
You can implement the Builder pattern by introducing a nested class Builder with a set of self-returning methods (i.e. returning an instance of Builder) which can be chained in a fluent way.
Method Builder.build() should return an instance of Person.
Note that you setters of your entities can be void.
That's how implementation might look like:
public class Person extends NamedEntity {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public static class Builder {
private Person person;
public Builder() {
this.person = new Person();
}
public Builder name(String name) {
person.setName(name);
return this;
}
public Builder address(String address) {
person.setAddress(address);
return this;
}
public Builder id(Integer id) {
person.setId(id);
return this;
}
public Person build() {
return person;
}
}
}
Usage example:
Person person = new Person.Builder()
.name("Alice")
.address("Wonderland")
.id(1)
.build();
Note:
There could be multiple ways to obtain an instance of Builder. You can introduce in the Person class a static method builder() returning a new Builder, or static methods like withName(String), withId(Integer) might also be handy (for inspiration have a look at User class from Spring Security).
When dialing with immutable objects, Builder class should have all the field of the target class duplicated instead of keeping the reference to the target object. And in such case, method build() would be responsible for constructing an instance of the target type.
When defining an abstract class, it is possible to create an instance of that class by writing the body of the abstract methods at object definition, like this:
AbstractClass obj = new AbstractClass() {
protected String description() { return this.description; }
};
I would like to do something similar, but inside the constructor of a sub-class. Something like this:
public class AbstractClass {
String description;
public AbstractClass(String description){
this.description = description;
}
protected abstract String description();
}
public class ActualClass extends AbstractClass {
public ActualClass(String description){
super(description) {
protected String description() { return this.description; }
};
}
}
Now, the code above doesn't work. How could I do something similar?
You don't do it in constructor, but in the class itself:
public abstract class AbstractClass {
String description;
public AbstractClass(String description){
this.description = description;
}
protected abstract String description();
}
public class ActualClass extends AbstractClass {
public ActualClass(String description){
super(description);
}
protected String description() {
return this.description;
}
}
How can I convert enum to POJO using mapstruct and without custom implementation?
e.g.
enum Type {
T1, T2;
private String description;
private Type(String description) {
this.description = description;
}
public String getDescription() { return this.description; }
}
to POJO like
class TypeDto {
private Type code;
private String description;
}
FYI,
I use MapStruct 1.1.0.Final.
I use this for now
default TypeDto typeToTypeDto(Type type) {
return new TypeDto(type.name(), type.getName());
}
due to lack of another solution.
You cannot directly convert from an enum to an object.
You would need to create a TypeMapper and an implementation to handle the conversion.
TypeConversion
public class TypeConversion {
public static void main(String[] args) {
TypeDto t1 = TypeMapper.INSTANCE.typeToTypeDto(Type.T1);
TypeDto t2 = TypeMapper.INSTANCE.typeToTypeDto(Type.T2);
System.out.println(t1);
System.out.println(t2);
}
}
Type
public enum Type {
T1("T-One"),
T2("T-Two");
private final String description;
private Type(String description) {
this.description = description;
}
public String getDescription() {
return this.description;
}
}
TypeDto
public class TypeDto {
private String description;
public TypeDto() {
this("");
}
public TypeDto(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Override
public String toString() {
return String.format("TypeDto { \"description\": \"%s\" }", description);
}
}
TypeMapper
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
#Mapper
public interface TypeMapper {
TypeMapper INSTANCE = Mappers.getMapper(TypeMapper.class);
#Mapping(source = "description", target = "description")
TypeDto typeToTypeDto(Type type);
}
TypeMapperImpl
public class TypeMapperImpl implements TypeMapper {
#Override
public TypeDto typeToTypeDto(Type type) {
if (type == null) {
return null;
}
return new TypeDto(type.getDescription());
}
}
You can make this mapper reusable by creating a generic mapper.
EnumMapper
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
#Mapper
public interface EnumMapper<T, U extends Enum<?>> {
#Mapping(target = "description")
T enumToObject(U type);
}
EnumMapperImpl
public abstract class EnumMapperImpl<T, U extends Enum<?>> implements EnumMapper<T, U> {
#Override
public T enumToObject(U type) {
if (type == null) {
return null;
}
return convert(type);
}
protected abstract T convert(U type);
}
Then you can use this in your TypeMapper.
TypeMapper
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
#Mapper
public interface TypeMapper extends EnumMapper<TypeDto, Type> {
TypeMapper INSTANCE = Mappers.getMapper(TypeMapper.class);
}
TypeMapperImpl
public class TypeMapperImpl extends EnumMapperImpl<TypeDto, Type> implements TypeMapper {
#Override
protected TypeDto convert(Type type) {
return new TypeDto(type.getDescription());
}
}
It's not something that MapStruct can automatically handle for you. Just implement the mapping by hand. MapStruct does not aim to handle every mapping case for you, but automate the common 80% and let you deal with the more exotic cases yourself.
I'm designing a DTO that will be serialized to JSON. The serializing framework kept complaining that all the members of my DTO should be public, and that the DTO should have public no-args CTOR.
I was wondering which of these two approaches is better, in your opinion, and why:
1) No getters/setters
public MyClass {
public int someField;
public String someOtherField;
}
2) All getters/setters
public MyClass {
private int someField;
private String someOtherField;
public int getSomeField() {
return someField;
}
public String getSomeOtherField() {
return someOtherField;
}
public void setSomeField(int someField) {
this.someField = someField;
}
public void setSomeOtherField(String someOtherField) {
this.someOtherField = someOtherField;
}
}