JSON serialiezr/deserializer for CustomerDTO - manually
This commit is contained in:
parent
35565e1b43
commit
bc87739d6f
@ -1,13 +1,41 @@
|
||||
package org.hostsharing.hsadminng.service.dto;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.TreeNode;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.node.IntNode;
|
||||
import com.fasterxml.jackson.databind.node.TextNode;
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.hostsharing.hsadminng.security.SecurityUtils;
|
||||
import org.springframework.boot.jackson.JsonComponent;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.validation.constraints.*;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
/**
|
||||
* A DTO for the Customer entity.
|
||||
*/
|
||||
@ReadableFor(Role.ANY_CUSTOMER_USER)
|
||||
@WritableFor(Role.SUPPORTER)
|
||||
public class CustomerDTO implements Serializable {
|
||||
|
||||
@WritableFor(Role.NOBODY)
|
||||
private Long id;
|
||||
|
||||
@NotNull
|
||||
@ -25,23 +53,21 @@ public class CustomerDTO implements Serializable {
|
||||
|
||||
@NotNull
|
||||
@Size(max = 400)
|
||||
// visible by >=contractual contact
|
||||
// changeable by >=supporter
|
||||
@ReadableFor(Role.CONTRACTUAL_CONTACT)
|
||||
private String contractualAddress;
|
||||
|
||||
@Size(max = 80)
|
||||
// visible by >=contractual contact
|
||||
// changeable by >=supporter
|
||||
@ReadableFor(Role.CONTRACTUAL_CONTACT)
|
||||
@WritableFor(Role.CONTRACTUAL_CONTACT)
|
||||
private String contractualSalutation;
|
||||
|
||||
@Size(max = 400)
|
||||
// visible by >=contractual contact | >=billing contact
|
||||
// changeable by >=contractual contact
|
||||
@ReadableFor(Role.CONTRACTUAL_CONTACT)
|
||||
private String billingAddress;
|
||||
|
||||
@Size(max = 80)
|
||||
// visible by >=contractual contact | >=billing contact
|
||||
// changeable by >=contractual contact
|
||||
@ReadableFor(Role.CONTRACTUAL_CONTACT)
|
||||
@WritableFor(Role.CONTRACTUAL_CONTACT)
|
||||
private String billingSalutation;
|
||||
|
||||
public Long getId() {
|
||||
@ -142,4 +168,133 @@ public class CustomerDTO implements Serializable {
|
||||
", billingSalutation='" + getBillingSalutation() + "'" +
|
||||
"}";
|
||||
}
|
||||
|
||||
@JsonComponent
|
||||
public static class CustomerJsonSerializer extends JsonSerializer<CustomerDTO> {
|
||||
|
||||
private Optional<String> login;
|
||||
|
||||
@PostConstruct
|
||||
public void getLoginUser() {
|
||||
this.login = SecurityUtils.getCurrentUserLogin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(CustomerDTO dto, JsonGenerator jsonGenerator,
|
||||
SerializerProvider serializerProvider) throws IOException {
|
||||
|
||||
jsonGenerator.writeStartObject();
|
||||
try {
|
||||
for (PropertyDescriptor prop : Introspector.getBeanInfo(CustomerDTO.class).getPropertyDescriptors()) {
|
||||
if (isRealProprety(prop)) {
|
||||
toJSon(dto, jsonGenerator, prop);
|
||||
}
|
||||
}
|
||||
} catch (IntrospectionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
//
|
||||
// jsonGenerator.writeNumberField("number", dto.getNumber());
|
||||
// jsonGenerator.writeStringField("prefix", dto.getPrefix());
|
||||
// jsonGenerator.writeStringField("name", dto.getName());
|
||||
// toJSonString(dto, jsonGenerator,"contractualAddress");
|
||||
// jsonGenerator.writeStringField("contractualSalutation", dto.getContractualSalutation());
|
||||
// jsonGenerator.writeStringField("billingAddress", dto.getBillingAddress());
|
||||
// jsonGenerator.writeStringField("billingSalutation", dto.getBillingSalutation());
|
||||
|
||||
jsonGenerator.writeEndObject();
|
||||
}
|
||||
|
||||
private boolean isRealProprety(PropertyDescriptor prop) {
|
||||
return prop.getWriteMethod() != null;
|
||||
}
|
||||
|
||||
private void toJSonString(CustomerDTO user, JsonGenerator jsonGenerator, String fieldName) throws IOException {
|
||||
if (isReadAllowed(fieldName)) {
|
||||
jsonGenerator.writeStringField(fieldName, user.getContractualAddress());
|
||||
}
|
||||
}
|
||||
|
||||
private void toJSon(CustomerDTO dto, JsonGenerator jsonGenerator, PropertyDescriptor prop) throws IOException {
|
||||
final String fieldName = prop.getName();
|
||||
if (isReadAllowed(fieldName)) {
|
||||
if (Integer.class.isAssignableFrom(prop.getPropertyType()) || int.class.isAssignableFrom(prop.getPropertyType())) {
|
||||
jsonGenerator.writeNumberField(fieldName, (int) invoke(dto, prop.getReadMethod()));
|
||||
} else if (Long.class.isAssignableFrom(prop.getPropertyType()) || long.class.isAssignableFrom(prop.getPropertyType())) {
|
||||
jsonGenerator.writeNumberField(fieldName, (long) invoke(dto, prop.getReadMethod()));
|
||||
} else if (String.class.isAssignableFrom(prop.getPropertyType())) {
|
||||
jsonGenerator.writeStringField(fieldName, (String) invoke(dto, prop.getReadMethod()));
|
||||
} else {
|
||||
throw new NotImplementedException("property type not yet implemented" + prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object invoke(Object dto, Method method) {
|
||||
try {
|
||||
return method.invoke(dto);
|
||||
} catch (IllegalAccessException|InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isReadAllowed(String fieldName) {
|
||||
if ( fieldName.equals("contractualAddress") ) {
|
||||
return login.map(user -> user.equals("admin")).orElse(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@JsonComponent
|
||||
public static class UserJsonDeserializer extends JsonDeserializer<CustomerDTO> {
|
||||
|
||||
@Override
|
||||
public CustomerDTO deserialize(JsonParser jsonParser,
|
||||
DeserializationContext deserializationContext) throws IOException,
|
||||
JsonProcessingException {
|
||||
|
||||
TreeNode treeNode = jsonParser.getCodec().readTree(jsonParser);
|
||||
|
||||
CustomerDTO dto = new CustomerDTO();
|
||||
dto.setId(((IntNode) treeNode.get("id")).asLong());
|
||||
dto.setNumber(((IntNode) treeNode.get("number")).asInt());
|
||||
dto.setPrefix(((TextNode) treeNode.get("prefix")).asText());
|
||||
dto.setName(((TextNode) treeNode.get("name")).asText());
|
||||
dto.setContractualAddress(((TextNode) treeNode.get("contractualAddress")).asText());
|
||||
dto.setContractualSalutation(((TextNode) treeNode.get("contractualSalutation")).asText());
|
||||
dto.setBillingAddress(((TextNode) treeNode.get("billingAddress")).asText());
|
||||
dto.setBillingSalutation(((TextNode) treeNode.get("billingSalutation")).asText());
|
||||
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Role {
|
||||
NOBODY(0), HOSTMASTER(1), ADMIN(2), SUPPORTER(3),
|
||||
ANY_CUSTOMER_CONTACT(10), CONTRACTUAL_CONTACT(11),
|
||||
ANY_CUSTOMER_USER(30);
|
||||
|
||||
private final int level;
|
||||
|
||||
Role(final int level) {
|
||||
this.level = level;
|
||||
}
|
||||
}
|
||||
|
||||
@Target({ElementType.FIELD, ElementType.TYPE_USE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@interface ReadableFor {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Target({ElementType.FIELD, ElementType.TYPE_USE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@interface WritableFor {
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,113 @@
|
||||
package org.hostsharing.hsadminng.service.dto;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.hostsharing.hsadminng.security.SecurityUtils;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.json.JsonTest;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@JsonTest
|
||||
@RunWith(SpringRunner.class)
|
||||
public class CustomerDTOUnitTest {
|
||||
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Test
|
||||
public void testSerializationAsCustomer() throws JsonProcessingException {
|
||||
|
||||
// given
|
||||
CustomerDTO given = createSomeCustomerDTO();
|
||||
givenLoginUser("customer");
|
||||
|
||||
// when
|
||||
String actual = objectMapper.writeValueAsString(given);
|
||||
|
||||
// then
|
||||
given.setContractualAddress(null);
|
||||
//given.setContractualSalutation(null);
|
||||
assertEquals(createExpectedJSon(given), actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeserializeAsCustomer() throws IOException {
|
||||
// given
|
||||
String json = "{\"id\":1234,\"number\":10001,\"prefix\":\"abc\",\"name\":\"Mein Name\",\"contractualAddress\":\"Eine Adresse\",\"contractualSalutation\":\"Hallo\",\"billingAddress\":\"Noch eine Adresse\",\"billingSalutation\":\"Moin\"}";
|
||||
givenLoginUser("customer");
|
||||
|
||||
// when
|
||||
CustomerDTO actual = objectMapper.readValue(json, CustomerDTO.class);
|
||||
|
||||
// then
|
||||
CustomerDTO expected = new CustomerDTO();
|
||||
expected.setId(1234L);
|
||||
expected.setNumber(10001);
|
||||
expected.setPrefix("abc");
|
||||
expected.setName("Mein Name");
|
||||
expected.setContractualAddress(null); // not allowed
|
||||
expected.setContractualSalutation("Hallo");
|
||||
expected.setBillingAddress("Noch eine Adresse");
|
||||
expected.setBillingSalutation("Moin");
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
private String createExpectedJSon(CustomerDTO dto) {
|
||||
String json = // the fields in alphanumeric order:
|
||||
toJSonFieldDefinitionIfPresent("billingAddress", dto.getBillingAddress()) +
|
||||
toJSonFieldDefinitionIfPresent("billingSalutation", dto.getBillingSalutation()) +
|
||||
toJSonFieldDefinitionIfPresent("contractualAddress", dto.getContractualAddress()) +
|
||||
toJSonFieldDefinitionIfPresent("contractualSalutation", dto.getContractualSalutation()) +
|
||||
toJSonFieldDefinitionIfPresent("id", dto.getId()) +
|
||||
toJSonFieldDefinitionIfPresent("name", dto.getName()) +
|
||||
toJSonFieldDefinitionIfPresent("number", dto.getNumber()) +
|
||||
toJSonFieldDefinitionIfPresent("prefix", dto.getPrefix());
|
||||
return "{" + json.substring(0, json.length() - 1) + "}";
|
||||
}
|
||||
|
||||
private String toJSonFieldDefinitionIfPresent(String name, String value) {
|
||||
return value != null ? inQuotes(name) + ":" + inQuotes(value) + "," : "";
|
||||
}
|
||||
|
||||
private String toJSonFieldDefinitionIfPresent(String name, Number value) {
|
||||
return value != null ? inQuotes(name) + ":" + value + "," : "";
|
||||
}
|
||||
|
||||
private String inQuotes(Object value) {
|
||||
return "\"" + value.toString() + "\"";
|
||||
}
|
||||
|
||||
private CustomerDTO createSomeCustomerDTO() {
|
||||
CustomerDTO given = new CustomerDTO();
|
||||
given.setId(1234L);
|
||||
given.setNumber(10001);
|
||||
given.setPrefix("abc");
|
||||
given.setName("Mein Name");
|
||||
given.setContractualAddress("Eine Adresse");
|
||||
given.setContractualSalutation("Hallo");
|
||||
given.setBillingAddress("Noch eine Adresse");
|
||||
given.setBillingSalutation("Moin");
|
||||
givenLoginUser("admin");
|
||||
return given;
|
||||
}
|
||||
|
||||
private void givenLoginUser(String userName) {
|
||||
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
|
||||
securityContext.setAuthentication(new UsernamePasswordAuthenticationToken(userName, userName));
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
Optional<String> login = SecurityUtils.getCurrentUserLogin();
|
||||
assertThat(login).describedAs("precondition failed").contains(userName);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user