Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

byte[] should be readable in persistent files Issue #72 #73

Merged
merged 8 commits into from
Aug 20, 2021
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package de.ppi.deepsampler.persistence.json;

import com.fasterxml.jackson.databind.module.SimpleModule;
import de.ppi.deepsampler.persistence.json.extension.PlainByteArrayDeserializer;
import de.ppi.deepsampler.persistence.json.extension.PlainByteArraySerializer;

/**
* This class bundles convenient Serializers for DeepSampler.
*
*/
public class DeepSamplerSpecificModule extends SimpleModule {

public DeepSamplerSpecificModule(){
addSerializer(byte[].class, new PlainByteArraySerializer());
addDeserializer(byte[].class, new PlainByteArrayDeserializer());

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import de.ppi.deepsampler.persistence.json.extension.PlainByteArrayDeserializer;
import de.ppi.deepsampler.persistence.json.extension.PlainByteArraySerializer;
import de.ppi.deepsampler.persistence.json.extension.DeserializationExtension;
import de.ppi.deepsampler.persistence.json.extension.SerializationExtension;

Expand Down Expand Up @@ -48,8 +50,11 @@ protected ObjectMapper createObjectMapper() {
objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);

objectMapper.registerModule(new ParameterNamesModule(JsonCreator.Mode.PROPERTIES));
objectMapper.registerModule(new JavaTimeModule());
objectMapper.registerModule(new DeepSamplerSpecificModule());

objectMapper.setDefaultTyping(new CustomTypeResolverBuilder(ObjectMapper.DefaultTyping.NON_CONCRETE_AND_ARRAYS, objectMapper.getPolymorphicTypeValidator()));

applyCustomExtensions(objectMapper);
Expand All @@ -70,7 +75,6 @@ private void applyCustomExtensions(final ObjectMapper objectMapper) {
final SerializationExtension<Object> serializationObjExtension = (SerializationExtension<Object>) serializationExtension;
simpleModule.addSerializer(serializationObjExtension.getTypeToSerialize(), serializationObjExtension.getJsonSerializer());
}

objectMapper.registerModule(simpleModule);

for (final Module module : moduleList) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package de.ppi.deepsampler.persistence.json.extension;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;

import java.io.IOException;
/**
* This Deserializer deserializes a byte[], that was serialized as a list of integers.
* This class comes in a bundle with {@link PlainByteArraySerializer}
*
*/
public class PlainByteArrayDeserializer extends JsonDeserializer<byte[]> {
@Override
public byte[] deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {

ObjectCodec oc = p.getCodec();
JsonNode node = oc.readTree(p);

if (node.isArray() && node.isEmpty()) {
return null;
}

byte[] returnValue = new byte[node.size()];
int i =0;
for (JsonNode value : node) {
returnValue[i]= (byte) value.asInt();
i++;
}

return returnValue;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package de.ppi.deepsampler.persistence.json.extension;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.type.WritableTypeId;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

import java.io.IOException;

/**
* This Serializer serializes byte[] as a list of integers for easier debugging.
* Jackson would otherwise serialize a byte[] as a base64-String.
* This class comes in a bundle with {@link PlainByteArrayDeserializer}
*/
public class PlainByteArraySerializer extends StdSerializer<byte[]> {


public PlainByteArraySerializer() {
super(byte[].class);
}

@Override
public void serialize(byte[] value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartArray();
for (byte b: value) {
gen.writeNumber(b );
}
gen.writeEndArray();
}

@Override
public void serializeWithType(byte[] value, JsonGenerator gen, SerializerProvider serializers, TypeSerializer typeSer) throws IOException {
WritableTypeId typeIdDef = typeSer.writeTypePrefix(gen,
typeSer.typeId(value, JsonToken.VALUE_EMBEDDED_OBJECT));
serialize(value,gen,serializers);
typeSer.writeTypeSuffix(gen, typeIdDef);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Date;
import java.time.LocalDateTime;

Expand Down Expand Up @@ -485,6 +488,33 @@ void testComboMatcherSecondArgument(Path tempFile) {
assertEquals("R1", result);
}

@Test
public void byteArrayCanBeRecordedAndLoaded() throws IOException {
Sampler.clear();

final TestService testServiceSampler = Sampler.prepare(TestService.class);
PersistentSample.of(testServiceSampler.getRandomByteArray(anyInt()));

byte[] expectedArray = getTestService().getRandomByteArray(42);
final String pathToFile = "./record/byteArrayCanBeRecordedAndLoaded.json";
final PersistentSampleManager source = PersistentSampler.source(JsonSourceManager.builder().buildWithFile(pathToFile));
source.record();

assertFalse(SampleRepository.getInstance().isEmpty());
Sampler.clear();
assertTrue(SampleRepository.getInstance().isEmpty());


PersistentSample.of(testServiceSampler.getRandomByteArray(anyInt()));

source.load();

assertFalse(SampleRepository.getInstance().isEmpty());
byte[] valueStubbedMethod = getTestService().getRandomByteArray(42);
assertArrayEquals(expectedArray ,valueStubbedMethod);
Files.delete(Paths.get(pathToFile));
}

@Test
public void mixPureJavaApiAndPersistenceApi(Path tempFile) {
final TestService testServiceSampler = Sampler.prepare(TestService.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2020 PPI AG (Hamburg, Germany)
* This program is made available under the terms of the MIT License.
*/

package de.ppi.deepsampler.provider.common;

import java.util.Arrays;
import java.util.Objects;

/**
* A very simple Bean that represents non primitive types in TestCases containing a byte[].
*/
public class TestBeanWithBytes {

private byte[] someBytes;

public TestBeanWithBytes() {
}

public TestBeanWithBytes(byte[] someBytes) {
this.someBytes = someBytes;
}

public byte[] getSomeBytes() {
return someBytes;
}

public void setSomeBytes(byte[] someBytes) {
this.someBytes = someBytes;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TestBeanWithBytes that = (TestBeanWithBytes) o;
return Arrays.equals(someBytes, that.someBytes);
}

@Override
public int hashCode() {
return Arrays.hashCode(someBytes);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,17 @@ public TestBeanWithoutEquals echoParameter(final TestBeanWithoutEquals someObjec
return someObjectWithoutEquals;
}

/**
* This method returns a non primitive parameter containing a byte[] if the method is not mocked.
* This Method is intended to be used in positive and negative tests.
*
* @param someObject The parameter that will be returned unchanged
* @return the unchanged parameter value
*/
public TestBeanWithBytes echoParameter(final TestBeanWithBytes someObject) {
return someObject;
}

/**
* This method is needed to test whether calls of void methods can be verified or not.
*
Expand Down Expand Up @@ -186,4 +197,14 @@ public Map<Integer, Integer> getMapOfIntegers() {

return map;
}


public byte[] getRandomByteArray(int size){

byte[] b = new byte[size];
new Random().nextBytes(b);
return b;

}

}