conditional operator possible in POJO class using annotations? - spring-boot

POJO Class:
#Component
public class Device {
#JsonAlias("is5G")
private String deviceType;
}
if devicetype is "4G" then "is5G" should be mapped with "N" else "Y". Possible to achieve this in POJO class using annotations?

You can do that with a custom converter
#JsonSerialize(converter = SerializeConverter.class)
#JsonDeserialize(converter = DeserializeConverter.class)
#JsonAlias("is5G")
private String deviceType;
Serialize
public class SerializeConverter extends StdConverter<String, String> {
#Override
public String convert(String value) {
return value != null && value.equals("is5G") ? "Y" : "N";
}
}
Deserialize
public class DeserializeConverter extends StdConverter<String, String> {
#Override
public String convert(String value) {
return value.equals("Y") ? "is5G" : null // or another value;
}
}

Related

Equivalent of Jackson's #JsonUnwrapped in Jsonb

I tried to implement the equivalent of Jacksons's #JsonUnwrapped in Jsonb (using Yasson) with this:
#Retention(RetentionPolicy.RUNTIME)
#JsonbTypeSerializer(UnwrappedJsonbSerializer.class)
public #interface JsonbUnwrapped {}
public class UnwrappedJsonbSerializer implements JsonbSerializer<Object> {
#Override
public void serialize(Object object, JsonGenerator generator, SerializationContext context) {
context.serialize(object, new UnwrappedJsonGenerator(generator));
}
}
public class UnwrappedJsonGenerator extends JsonGeneratorWrapper {
private int level;
public UnwrappedJsonGenerator(JsonGenerator delegate) {
super(delegate);
}
#Override
public JsonGenerator writeStartObject(String name) {
return level++ == 0 ? this : super.writeStartObject(name);
}
#Override
public JsonGenerator writeStartArray(String name) {
return level++ == 0 ? this : super.writeStartArray(name);
}
#Override
public JsonGenerator writeEnd() {
return --level == 0 ? this : super.writeEnd();
}
}
public class Person {
#JsonbUnwrapped
public Name getName() {
return new Name();
}
public static class Name {
public String getFirstName() {
return "John";
}
public String getLastName() {
return "Doe";
}
}
}
JsonbBuilder.create().toJson(new Person())
But this raises an exception javax.json.bind.JsonbException: Recursive reference has been found in class class Person$Name because my UnwrappedJsonbSerializer calls SerializationContext.serialize() with the same object that was initially passed.
Is there any other way to achieve that without resorting to custom serializers for Person or Name ?

Fix string contraints on JPA entity attribute

I am new in JPA,
I want to set only specific fix department names to attribute in entity as a fix string as constraints.I.e default values to attributes.
How to set it?
I think the best option is to use enumerated as indicated by Dinesh Dontha, try this:
Entity
#Entity
public class MyEntity implements Serializable(){
private MyEnum attribute;
}
Enum
public enum MyEnum {
NAME1("N1")
private String shortName;
private MyEnum(String shortName) {
this.shortName = shortName;
}
public String getShortName() {
return shortName;
}
public static MyEnum fromShortName(String shortName) {
switch (shortName) {
case "N1":
return NacionalidadEnum.NAME1;
default:
throw new IllegalArgumentException("ShortName [" + shortName
+ "] not supported.");
}
}
}
Converter
#Converter(autoApply = true)
public class MyEntityEnumConverter implements AttributeConverter<MyEnum, String> {
#Override
public String convertToDatabaseColumn(MyEnum myEnum) {
return myEnum.getShortName();
}
#Override
public MyEnum convertToEntityAttribute(String dbData) {
return MyEnum.fromShortName(dbData);
}
}

Spring converter can't be diseable conditional

i use a Converter for OffsetDateTime for store they in SQLServer , but I dont want use it on H2, so i have try many think but it never work is always active....
My converter :
#Conditional(OffsetDateTimeConverterCondition.class)
#Converter(autoApply = true)
public class OffsetDateTimeConverter implements AttributeConverter<OffsetDateTime, String> {
private static final DateTimeFormatter FORMATTER_FROM_DB
= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.nnnnnnn xxx");
private static final DateTimeFormatter FORMATTER_TO_DB
= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.nnnnnnnnn xxx");
#Override
public String convertToDatabaseColumn(OffsetDateTime attribute) {
return attribute == null ? null : attribute.format(FORMATTER_TO_DB);
}
#Override
public OffsetDateTime convertToEntityAttribute(String dbData) {
return dbData == null ? null : OffsetDateTime.parse(dbData, FORMATTER_FROM_DB);
}
}
My class of condition :
public class OffsetDateTimeConverterCondition extends AnyNestedCondition {
public OffsetDateTimeConverterCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}
#ConditionalOnProperty(name = "required.datasource.dbms", havingValue = "SQLSERVER")
static class SQLSERVERCondition {
}
#ConditionalOnProperty(name = "required.datasource.dbms", havingValue = "ORACLE")
static class ORACLECondition {
}
}
I have try to :
#Configuration
public class OffsetDateTimeConverterCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return Arrays.asList(DBMS.SQLSERVER.name(), DBMS.ORACLE.name())
.contains(context.getEnvironment()
.getProperty("required.datasource.dbms"));
}
}
The setting is correctly set to SQLSERVER or H2, OffsetDateTimeConverterCondition return false when I am on H2 but it style active.

Converter works for RequestParameter but not for RequestBody field

I have the following converter:
#Component
public class CountryEnumConverter implements Converter<String, CountryEnum> {
#Override
public CountryEnum convert(String country) {
CountryEnum countryEnum = CountryEnum.getBySign(country);
if (countryEnum == null) {
throw new IllegalArgumentException(country + " - Country is not supported!");
}
return countryEnum;
}
}
Registered it is invoked when used for RequestParam
#GetMapping(value = RestApiEndpoints.RESULTS, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ResultDto> getResults(
Principal principal,
#RequestParam CountryEnum country) {
....
}
But this converter is never invoked when used for field in the RequstBody:
#GetMapping(value = RestApiEndpoints.RESULTS, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ResultDto> getResults(
Principal principal,
#RequestBody MyBody myBody) {
....
}
public class MyBody {
#NotNull
private CountryEnum country;
public MyBody() {
}
public CountryEnum getCountry() {
return country;
}
public void setCountry(CountryEnum country) {
this.country = country;
}
}
Your existing org.springframework.core.convert.converter.Converter instance will only work with data submitted as form encoded data. With #RequestBody you are sending JSON data which will be deserialized using using the Jackson library.
You can then create an instance of com.fasterxml.jackson.databind.util.StdConverter<IN, OUT>
public class StringToCountryTypeConverter extends StdConverter<String, CountryType> {
#Override
public CountryType convert(String value) {
//convert and return
}
}
and then apply this on the target property:
public class MyBody {
#NotNull
#JsonDeserialize(converter = StringToCountryTypeConverter.class)
private CountryEnum country;
}
Given the similarity of the 2 interfaces I would expect that you could create one class to handle both scenarios:
public class StringToCountryTypeConverter extends StdConverter<String, CountryType>
implements org.springframework.core.convert.converter.Converter<String, CountryType> {
#Override
public CountryType convert(String value) {
//convert and return
}
}
I found out that if I add the following code to my CountryEnum will do the trick.
#JsonCreator
public static CountryEnum fromString(String value) {
CountryEnumConverter converter = new CountryEnumConverter();
return converter.convert(value);
}

Spring Method Level security Getting null Property EL1007E: Property or field 'price' cannot be found on null

My Model Class is
#Data
public class Beer {
public Beer(int i, String string, float d) {
this.beerId = i;
this.beerName = string;
this.price = d;
}
public Beer() {
}
private int beerId;
private String beerName;
private float price;
}
And the Service Interface is
public interface IBeerService {
#Secured("ROLE_ADMIN")
#PreAuthorize("#beer.price > 0.0f")
Beer add(Beer beer);
#Secured("ROLE_USER")
#RolesAllowed("ROLE_USER")
List<Beer> getAll();
}
The interface is implemented as below.
#Service
public class BeerService implements IBeerService {
private List<Beer> beerRepository = new ArrayList<>();
#Override
public Beer add(Beer beerToAdd) {
if(!beerRepository.contains(beerToAdd)) {
beerToAdd.setBeerId(this.beerRepository.size()+1);
this.beerRepository.add(beerToAdd);
}
return beerToAdd;
}
#Override
public List<Beer> getAll() {
return beerRepository;
}
}
In the controller, I can able to see the object which is not null, in the debugger.
I am getting an error as
org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'price' cannot be found on null
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:213) ~[spring-expression-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:104) ~[spring-expression-5.1.9.RELEASE.jar:5.1.9.RELEASE]

Resources