Skip to content

Problems with boolean serialization/deserialization #699

@esalsbury

Description

@esalsbury

Using 5.0.0-RC4 version. Here is the basic pool setup:

private final Pool<Kryo> kryoPool = new Pool<Kryo>(true, true) {

			@Override
			public Kryo create() {
				Kryo kryo = new KryoReflectionFactorySupport();
				kryo.setDefaultSerializer(new SerializerFactory.BaseSerializerFactory() {
					@Override
					public Serializer newSerializer(Kryo kryo, Class type) {
						CompatibleFieldSerializer.CompatibleFieldSerializerConfig config = new CompatibleFieldSerializer.CompatibleFieldSerializerConfig();
						config.setChunkedEncoding(true);
						config.setReadUnknownFieldData(true);
						CompatibleFieldSerializer serializer = new CompatibleFieldSerializer(kryo, type, config);
						return serializer;
					}
				});
				kryo.setRegistrationRequired(false);
				kryo.setInstantiatorStrategy(new DefaultInstantiatorStrategy(new SerializingInstantiatorStrategy()));

IdValidatingKryoRegistrar registrar = new IdValidatingKryoRegistrar(kryo, RESERVED_KRYO_IDS);
				for (KryoInitializer initializer : initializers) {
					initializer.initialize(registrar);
				}

				return kryo;
			}

Serialize method:

public byte[] serialize(final Object object) throws SerializationException {
		Kryo kryo = kryoPool.obtain();
		try {
			ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
			Output output = new Output(baos);
			kryo.writeObject(output, object);
			output.close();

			return baos.toByteArray();
		} finally {
			kryoPool.free(kryo);
		}
	}

Deserialize method:

	public <T> T deserialize(final byte[] bytes, Class<T> clazz) throws DeserializationException {
		Kryo kryo = kryoPool.obtain();
		try {
			ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
			Input input = new Input(bais);
			T object = kryo.readObject(input, clazz);
			input.close();
			return object;
		} finally {
			kryoPool.free(kryo);
		}
	}

I can reliably cause a failure with the following test where I serialize and immediately deserialize an object:

	@Test
	public void testBrokenObjectABunchOfTimes() {
		Foo foo = new Foo();
		foo.setAccountId(-8490936757185012249L);
		foo.setConversionType(CustomEnum.Custom);
		foo.setCustomNote(true);
		foo.setEmployeeId(4625218007351340003L);
		foo.setExpireLevelLicenses(false);
		foo.setOtherAccountId(-8463767768599195457L);
		foo.setOtherAccountName("sit");
		foo.setOtherProgram(OtherProgramType.Program);
		foo.setOtherRegion(RegionId.EU);
		foo.setIpAddr("sit");
		foo.setLink(false);
		foo.setLocalOnly(false);
		foo.setNewAccountId(-1925026497398518482L);
		SkipEmailFlagsADT emailFlagsADT = new SkipEmailFlagsADT();
		emailFlagsADT.setSkipAccountEmail(false);
		emailFlagsADT.setSkipOtherAccountEmail(true);
		foo.setSkipEmailFlags(emailFlagsADT);
		foo.setSkipPaymentReversalCheck(true);
		int successes = 0;
		int failures = 0;
		int totalRuns = 10000;
		for (int i = 0; i < totalRuns; i++) {
			byte[] bytes = payloadConverter.serialize(foo);
			Foo output = payloadConverter.deserialize(bytes, Foo.class);
			if (DeepEquals.deepEquals(foo, output)) {
				successes++;
			} else {
				failures++;
			}
		}
		System.out.println("Total Runs: " + totalRuns);
		System.out.println("Successes: " + successes);
		System.out.println("Failures: " + failures);
	}

This produces the following comparison objects:
Before Serialize/Deserialize:
[accountId = -8490936757185012249, conversionType = Custom, customNote = true, employeeId = 4625218007351340003, expireLevelLicenses = false, otherAccountId = -8463767768599195457, otherAccountName = sit, otherProgram = Program, otherRegion = EU, ipAddr = sit, link = false, localOnly = false, newAccountId = -1925026497398518482, skipEmailFlags = com.object.path.SkipEmailFlagsADT [skipAccountEmail = false, skipOtherAccountEmail = true], skipPaymentReversalCheck = true])

After Serialize/Deserialize:
[accountId = -8490936757185012249, conversionType = Custom, customNote = false, employeeId = 4625218007351340003, expireLevelLicenses = false, otherAccountId = -8463767768599195457, otherAccountName = sit, otherProgram = Program, otherRegion = EU, ipAddr = sit, link = false, localOnly = false, newAccountId = -1925026497398518482, skipEmailFlags = com.object.path.SkipEmailFlagsADT [skipAccountEmail = false, skipOtherAccountEmail = true], skipPaymentReversalCheck = true])

Everytime this runs, the customNote boolean field flips from true to false.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions