JSON serializer generalized
This commit is contained in:
		@@ -14,60 +14,55 @@ 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.Field;
 | 
			
		||||
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)
 | 
			
		||||
    @AccessFor(read = Role.ANY_CUSTOMER_USER)
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    @Min(value = 10000)
 | 
			
		||||
    @Max(value = 99999)
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, read = Role.ANY_CUSTOMER_USER)
 | 
			
		||||
    private Integer number;
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    @Pattern(regexp = "[a-z][a-z0-9]+")
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, read = Role.ANY_CUSTOMER_USER)
 | 
			
		||||
    private String prefix;
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    @Size(max = 80)
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, read = Role.ANY_CUSTOMER_USER)
 | 
			
		||||
    private String name;
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    @Size(max = 400)
 | 
			
		||||
    @ReadableFor(Role.CONTRACTUAL_CONTACT)
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = Role.CONTRACTUAL_CONTACT)
 | 
			
		||||
    private String contractualAddress;
 | 
			
		||||
 | 
			
		||||
    @Size(max = 80)
 | 
			
		||||
    @ReadableFor(Role.CONTRACTUAL_CONTACT)
 | 
			
		||||
    @WritableFor(Role.CONTRACTUAL_CONTACT)
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, update = Role.CONTRACTUAL_CONTACT, read = Role.ANY_CUSTOMER_CONTACT)
 | 
			
		||||
    private String contractualSalutation;
 | 
			
		||||
 | 
			
		||||
    @Size(max = 400)
 | 
			
		||||
    @ReadableFor(Role.CONTRACTUAL_CONTACT)
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = Role.CONTRACTUAL_CONTACT)
 | 
			
		||||
    private String billingAddress;
 | 
			
		||||
 | 
			
		||||
    @Size(max = 80)
 | 
			
		||||
    @ReadableFor(Role.CONTRACTUAL_CONTACT)
 | 
			
		||||
    @WritableFor(Role.CONTRACTUAL_CONTACT)
 | 
			
		||||
    @AccessFor(init = Role.ADMIN, update = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}, read = Role.CONTRACTUAL_CONTACT)
 | 
			
		||||
    private String billingSalutation;
 | 
			
		||||
 | 
			
		||||
    public Long getId() {
 | 
			
		||||
@@ -172,79 +167,54 @@ public class CustomerDTO implements Serializable {
 | 
			
		||||
    @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);
 | 
			
		||||
            for (Field prop : CustomerDTO.class.getDeclaredFields()) {
 | 
			
		||||
                toJSon(dto, jsonGenerator, prop);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
//            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()));
 | 
			
		||||
        private void toJSon(CustomerDTO dto, JsonGenerator jsonGenerator, Field prop) throws IOException {
 | 
			
		||||
            if (getLoginUserRole().isAllowedToRead(prop)) {
 | 
			
		||||
                final String fieldName = prop.getName();
 | 
			
		||||
                if (Integer.class.isAssignableFrom(prop.getType()) || int.class.isAssignableFrom(prop.getType())) {
 | 
			
		||||
                    jsonGenerator.writeNumberField(fieldName, (int) get(dto, prop));
 | 
			
		||||
                } else if (Long.class.isAssignableFrom(prop.getType()) || long.class.isAssignableFrom(prop.getType())) {
 | 
			
		||||
                    jsonGenerator.writeNumberField(fieldName, (long) get(dto, prop));
 | 
			
		||||
                } else if (String.class.isAssignableFrom(prop.getType())) {
 | 
			
		||||
                    jsonGenerator.writeStringField(fieldName, (String) get(dto, prop));
 | 
			
		||||
                } else {
 | 
			
		||||
                    throw new NotImplementedException("property type not yet implemented" + prop);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Object invoke(Object dto, Method method) {
 | 
			
		||||
        private Object get(CustomerDTO dto, Field field) {
 | 
			
		||||
            try {
 | 
			
		||||
                return method.invoke(dto);
 | 
			
		||||
            } catch (IllegalAccessException|InvocationTargetException e) {
 | 
			
		||||
                field.setAccessible(true);
 | 
			
		||||
                return field.get(dto);
 | 
			
		||||
            } catch (IllegalAccessException 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;
 | 
			
		||||
        private Role getLoginUserRole() {
 | 
			
		||||
            return SecurityUtils.getCurrentUserLogin().map(u -> Role.valueOf(u.toUpperCase())).orElse(Role.ANYBODY);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Object invoke(Object dto, Method method) {
 | 
			
		||||
            try {
 | 
			
		||||
                return method.invoke(dto);
 | 
			
		||||
            } catch (IllegalAccessException | InvocationTargetException e) {
 | 
			
		||||
                throw new RuntimeException(e);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @JsonComponent
 | 
			
		||||
@@ -274,27 +244,73 @@ public class CustomerDTO implements Serializable {
 | 
			
		||||
 | 
			
		||||
enum Role {
 | 
			
		||||
    NOBODY(0), HOSTMASTER(1), ADMIN(2), SUPPORTER(3),
 | 
			
		||||
    ANY_CUSTOMER_CONTACT(10), CONTRACTUAL_CONTACT(11),
 | 
			
		||||
    ANY_CUSTOMER_USER(30);
 | 
			
		||||
    ANY_CUSTOMER_CONTACT(20), CONTRACTUAL_CONTACT(21), FINANCIAL_CONTACT(22), TECHNICAL_CONTACT(22),
 | 
			
		||||
    ANY_CUSTOMER_USER(80),
 | 
			
		||||
    ANYBODY(99);
 | 
			
		||||
 | 
			
		||||
    private final int level;
 | 
			
		||||
 | 
			
		||||
    Role(final int level) {
 | 
			
		||||
        this.level = level;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    boolean covers(final Role role) {
 | 
			
		||||
        return this == role || this.level < role.level;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isAllowedToInit(Field field) {
 | 
			
		||||
 | 
			
		||||
        final AccessFor accessFor = field.getAnnotation(AccessFor.class);
 | 
			
		||||
        if (accessFor == null) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return isRoleCovered(accessFor.init());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isAllowedToUpdate(Field field) {
 | 
			
		||||
 | 
			
		||||
        final Role loginUserRole = SecurityUtils.getCurrentUserLogin().map(u -> Role.valueOf(u.toUpperCase())).orElse(Role.ANYBODY);
 | 
			
		||||
 | 
			
		||||
        final AccessFor accessFor = field.getAnnotation(AccessFor.class);
 | 
			
		||||
        if (accessFor == null) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return isRoleCovered(accessFor.update());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isAllowedToRead(Field field) {
 | 
			
		||||
 | 
			
		||||
        final Role loginUserRole = SecurityUtils.getCurrentUserLogin().map(u -> Role.valueOf(u.toUpperCase())).orElse(Role.ANYBODY);
 | 
			
		||||
 | 
			
		||||
        final AccessFor accessFor = field.getAnnotation(AccessFor.class);
 | 
			
		||||
        if (accessFor == null) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return isRoleCovered(accessFor.read());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean isRoleCovered(Role[] requiredRoles) {
 | 
			
		||||
        for (Role accessAllowedForRole : requiredRoles) {
 | 
			
		||||
            if (this.covers(accessAllowedForRole)) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Target({ElementType.FIELD, ElementType.TYPE_USE})
 | 
			
		||||
@Retention(RetentionPolicy.RUNTIME)
 | 
			
		||||
@Documented
 | 
			
		||||
@interface ReadableFor {
 | 
			
		||||
@interface AccessFor {
 | 
			
		||||
    Role[] init() default Role.NOBODY;
 | 
			
		||||
 | 
			
		||||
    Role[] update() default Role.NOBODY;
 | 
			
		||||
 | 
			
		||||
    Role[] read() default Role.NOBODY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@Target({ElementType.FIELD, ElementType.TYPE_USE})
 | 
			
		||||
@Retention(RetentionPolicy.RUNTIME)
 | 
			
		||||
@Documented
 | 
			
		||||
@interface WritableFor {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user