parallel structure for JSonSerializer/DeserializerWithAccessFilter
This commit is contained in:
parent
90316a262b
commit
bb0fb4aa78
@ -20,9 +20,10 @@ public class JSonDeserializerWithAccessFilter<T> {
|
|||||||
|
|
||||||
public JSonDeserializerWithAccessFilter(final JsonParser jsonParser, final DeserializationContext deserializationContext, Class<T> dtoClass) {
|
public JSonDeserializerWithAccessFilter(final JsonParser jsonParser, final DeserializationContext deserializationContext, Class<T> dtoClass) {
|
||||||
this.treeNode = unchecked(() -> jsonParser.getCodec().readTree(jsonParser));
|
this.treeNode = unchecked(() -> jsonParser.getCodec().readTree(jsonParser));
|
||||||
this.dto = unchecked(() -> dtoClass.newInstance());
|
this.dto = unchecked(dtoClass::newInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Jackson deserializes from the JsonParser, thus no input parameter needed.
|
||||||
public T deserialize() {
|
public T deserialize() {
|
||||||
treeNode.fieldNames().forEachRemaining(fieldName -> {
|
treeNode.fieldNames().forEachRemaining(fieldName -> {
|
||||||
try {
|
try {
|
||||||
|
@ -13,21 +13,26 @@ import java.lang.reflect.Field;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
@JsonComponent
|
public class JSonSerializerWithAccessFilter <T> {
|
||||||
public class JSonSerializerWithAccessFilter extends JsonSerializer<Object> {
|
private final JsonGenerator jsonGenerator;
|
||||||
|
private final SerializerProvider serializerProvider;
|
||||||
|
private final T dto;
|
||||||
|
|
||||||
@Override
|
public JSonSerializerWithAccessFilter(final JsonGenerator jsonGenerator,
|
||||||
public void serialize(final Object dto, final JsonGenerator jsonGenerator,
|
final SerializerProvider serializerProvider,
|
||||||
final SerializerProvider serializerProvider) throws IOException {
|
final T dto) {
|
||||||
|
this.jsonGenerator = jsonGenerator;
|
||||||
|
this.serializerProvider = serializerProvider;
|
||||||
|
this.dto = dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jackson serializes into the JsonGenerator, thus no return value needed.
|
||||||
|
public void serialize() throws IOException {
|
||||||
|
|
||||||
// TODO: Move the implementation to an (if necessary, inner) class, or maybe better
|
|
||||||
// expose just the inner implementation from an explicit @JsonCompontent
|
|
||||||
// as it's necessary for the deserializers anyway.
|
|
||||||
jsonGenerator.writeStartObject();
|
jsonGenerator.writeStartObject();
|
||||||
for (Field prop : dto.getClass().getDeclaredFields()) {
|
for (Field prop : dto.getClass().getDeclaredFields()) {
|
||||||
toJSon(dto, jsonGenerator, prop);
|
toJSon(dto, jsonGenerator, prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonGenerator.writeEndObject();
|
jsonGenerator.writeEndObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,9 +40,10 @@ public class JSonSerializerWithAccessFilter extends JsonSerializer<Object> {
|
|||||||
if (getLoginUserRole().isAllowedToRead(prop)) {
|
if (getLoginUserRole().isAllowedToRead(prop)) {
|
||||||
final String fieldName = prop.getName();
|
final String fieldName = prop.getName();
|
||||||
// TODO: maybe replace by serializerProvider.defaultSerialize...()?
|
// TODO: maybe replace by serializerProvider.defaultSerialize...()?
|
||||||
// But that's difficult for parallel structure with the deserializer, where the API is ugly.
|
// But that makes it difficult for parallel structure with the deserializer (clumsy API).
|
||||||
// Alternatively extract the supported types to subclasses of some abstract class and
|
// Alternatively extract the supported types to subclasses of some abstract class and
|
||||||
// here as well as in the deserializer just access the matching implementation through a map.
|
// here as well as in the deserializer just access the matching implementation through a map.
|
||||||
|
// Or even completely switch from Jackson to GSON?
|
||||||
if (Integer.class.isAssignableFrom(prop.getType()) || int.class.isAssignableFrom(prop.getType())) {
|
if (Integer.class.isAssignableFrom(prop.getType()) || int.class.isAssignableFrom(prop.getType())) {
|
||||||
jsonGenerator.writeNumberField(fieldName, (int) get(dto, prop));
|
jsonGenerator.writeNumberField(fieldName, (int) get(dto, prop));
|
||||||
} else if (Long.class.isAssignableFrom(prop.getType()) || long.class.isAssignableFrom(prop.getType())) {
|
} else if (Long.class.isAssignableFrom(prop.getType()) || long.class.isAssignableFrom(prop.getType())) {
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
package org.hostsharing.hsadminng.service.dto;
|
package org.hostsharing.hsadminng.service.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
import com.fasterxml.jackson.core.JsonParser;
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
import com.fasterxml.jackson.core.TreeNode;
|
import com.fasterxml.jackson.core.TreeNode;
|
||||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
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.IntNode;
|
||||||
import com.fasterxml.jackson.databind.node.TextNode;
|
import com.fasterxml.jackson.databind.node.TextNode;
|
||||||
import org.hostsharing.hsadminng.service.accessfilter.AccessFor;
|
import org.hostsharing.hsadminng.service.accessfilter.AccessFor;
|
||||||
import org.hostsharing.hsadminng.service.accessfilter.JSonDeserializerWithAccessFilter;
|
import org.hostsharing.hsadminng.service.accessfilter.JSonDeserializerWithAccessFilter;
|
||||||
|
import org.hostsharing.hsadminng.service.accessfilter.JSonSerializerWithAccessFilter;
|
||||||
import org.hostsharing.hsadminng.service.accessfilter.Role;
|
import org.hostsharing.hsadminng.service.accessfilter.Role;
|
||||||
import org.springframework.boot.jackson.JsonComponent;
|
import org.springframework.boot.jackson.JsonComponent;
|
||||||
|
|
||||||
@ -171,13 +175,26 @@ public class CustomerDTO implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JsonComponent
|
@JsonComponent
|
||||||
public static class UserJsonDeserializer extends JsonDeserializer<CustomerDTO> {
|
public static class CustomerJsonSerializer extends JsonSerializer<CustomerDTO> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(final CustomerDTO customerDTO, final JsonGenerator jsonGenerator,
|
||||||
|
final SerializerProvider serializerProvider) throws IOException {
|
||||||
|
|
||||||
|
new JSonSerializerWithAccessFilter<>(jsonGenerator, serializerProvider, customerDTO).serialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@JsonComponent
|
||||||
|
public static class CustomerJsonDeserializer extends JsonDeserializer<CustomerDTO> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CustomerDTO deserialize(final JsonParser jsonParser,
|
public CustomerDTO deserialize(final JsonParser jsonParser,
|
||||||
final DeserializationContext deserializationContext) {
|
final DeserializationContext deserializationContext) {
|
||||||
|
|
||||||
return new JSonDeserializerWithAccessFilter<>(jsonParser, deserializationContext, CustomerDTO.class).deserialize();
|
return new JSonDeserializerWithAccessFilter<>(jsonParser, deserializationContext, CustomerDTO.class).deserialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ public class JSonSerializerWithAccessFilterUnitTest {
|
|||||||
@Test
|
@Test
|
||||||
public void shouldSerializeStringField() throws IOException {
|
public void shouldSerializeStringField() throws IOException {
|
||||||
// when
|
// when
|
||||||
new JSonSerializerWithAccessFilter().serialize(givenDTO, jsonGenerator, null);
|
new JSonSerializerWithAccessFilter<>(jsonGenerator, null, givenDTO).serialize();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(jsonGenerator).writeStringField("openStringField", givenDTO.openStringField);
|
verify(jsonGenerator).writeStringField("openStringField", givenDTO.openStringField);
|
||||||
@ -50,10 +50,10 @@ public class JSonSerializerWithAccessFilterUnitTest {
|
|||||||
givenLoginUserWithRole(Role.FINANCIAL_CONTACT);
|
givenLoginUserWithRole(Role.FINANCIAL_CONTACT);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
new JSonSerializerWithAccessFilter().serialize(givenDTO, jsonGenerator, null);
|
new JSonSerializerWithAccessFilter<>(jsonGenerator, null, givenDTO).serialize();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(jsonGenerator).writeStringField("restrictedField", givenDTO.restrictedField);
|
verify(jsonGenerator).writeStringField("restrictedField", givenDTO.restrictedField);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -63,25 +63,26 @@ public class JSonSerializerWithAccessFilterUnitTest {
|
|||||||
givenLoginUserWithRole(Role.ANY_CUSTOMER_USER);
|
givenLoginUserWithRole(Role.ANY_CUSTOMER_USER);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
new JSonSerializerWithAccessFilter().serialize(givenDTO, jsonGenerator, null);
|
new JSonSerializerWithAccessFilter<>(jsonGenerator, null, givenDTO).serialize();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(jsonGenerator, never()).writeStringField("restrictedField", givenDTO.restrictedField);
|
verify(jsonGenerator, never()).writeStringField("restrictedField", givenDTO.restrictedField);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldThrowExceptionForUnimplementedFieldType() throws IOException {
|
public void shouldThrowExceptionForUnimplementedFieldType() {
|
||||||
|
|
||||||
// given
|
// given
|
||||||
class Arbitrary {}
|
class Arbitrary {
|
||||||
|
}
|
||||||
class GivenDtoWithUnimplementedFieldType {
|
class GivenDtoWithUnimplementedFieldType {
|
||||||
@AccessFor(read = Role.ANYBODY)
|
@AccessFor(read = Role.ANYBODY)
|
||||||
Arbitrary fieldWithUnimplementedType;
|
Arbitrary fieldWithUnimplementedType;
|
||||||
}
|
}
|
||||||
final GivenDtoWithUnimplementedFieldType givenDto = new GivenDtoWithUnimplementedFieldType();
|
final GivenDtoWithUnimplementedFieldType givenDtoWithUnimplementedFieldType = new GivenDtoWithUnimplementedFieldType();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
Throwable actual = catchThrowable(() -> new JSonSerializerWithAccessFilter().serialize(givenDto, jsonGenerator, null));
|
Throwable actual = catchThrowable(() -> new JSonSerializerWithAccessFilter<>(jsonGenerator, null, givenDtoWithUnimplementedFieldType).serialize());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(actual).isInstanceOf(NotImplementedException.class);
|
assertThat(actual).isInstanceOf(NotImplementedException.class);
|
||||||
|
Loading…
Reference in New Issue
Block a user