Skip to content

Commit

Permalink
Merge pull request EsotericSoftware#297 from timotta/master
Browse files Browse the repository at this point in the history
Warn unregistered classes option
  • Loading branch information
magro committed Jun 7, 2016
2 parents ad20b60 + fd7d1b2 commit cf253eb
Show file tree
Hide file tree
Showing 2 changed files with 188 additions and 2 deletions.
27 changes: 25 additions & 2 deletions src/com/esotericsoftware/kryo/Kryo.java
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ public class Kryo {
private ClassLoader classLoader = getClass().getClassLoader();
private InstantiatorStrategy strategy = new DefaultInstantiatorStrategy();
private boolean registrationRequired;
private boolean warnUnregisteredClasses;

private int depth, maxDepth = Integer.MAX_VALUE;
private boolean autoReset = true;
Expand Down Expand Up @@ -499,15 +500,22 @@ public Registration getRegistration (Class type) {
}
if (registration == null) {
if (registrationRequired) {
throw new IllegalArgumentException("Class is not registered: " + className(type)
+ "\nNote: To register this class use: kryo.register(" + className(type) + ".class);");
throw new IllegalArgumentException(unregisteredClassMessage(type));
}
if(warnUnregisteredClasses) {
warn(unregisteredClassMessage(type));
}
registration = classResolver.registerImplicit(type);
}
}
return registration;
}

protected String unregisteredClassMessage (Class type) {
return "Class is not registered: " + className(type)
+ "\nNote: To register this class use: kryo.register(" + className(type) + ".class);";
}

/** @see ClassResolver#getRegistration(int) */
public Registration getRegistration (int classID) {
return classResolver.getRegistration(classID);
Expand Down Expand Up @@ -1040,6 +1048,21 @@ public void setRegistrationRequired (boolean registrationRequired) {
public boolean isRegistrationRequired () {
return registrationRequired;
}

/**
* If true, kryo writes a warn log telling about the classes unregistered. Default is false.
* <p>
* If false, no log are written when unregistered classes are encountered.
* </p>
*/
public void setWarnUnregisteredClasses (boolean warnUnregisteredClasses) {
this.warnUnregisteredClasses = warnUnregisteredClasses;
if (TRACE) trace("kryo", "Warn unregistered classes: " + warnUnregisteredClasses);
}

public boolean isWarnUnregisteredClasses () {
return warnUnregisteredClasses;
}

/** If true, each appearance of an object in the graph after the first is stored as an integer ordinal. When set to true,
* {@link MapReferenceResolver} is used. This enables references to the same object and cyclic graphs to be serialized, but
Expand Down
163 changes: 163 additions & 0 deletions test/com/esotericsoftware/kryo/WarnUnregisteredClassesTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/* Copyright (c) 2008, Nathan Sweet
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided with the distribution.
* - Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

package com.esotericsoftware.kryo;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
import java.util.List;
import java.util.TimeZone;

import com.esotericsoftware.kryo.KryoTestCase.StreamFactory;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.io.UnsafeMemoryInput;
import com.esotericsoftware.kryo.io.UnsafeMemoryOutput;
import com.esotericsoftware.minlog.Log;

import static com.esotericsoftware.minlog.Log.Logger;

import java.util.Locale;

import junit.framework.TestCase;

/** @author Tiago Albineli Motta <[email protected]> */
public class WarnUnregisteredClassesTest extends TestCase {

LoggerStub log;

@Override
protected void setUp() throws Exception {
super.setUp();
log = new LoggerStub();
Log.setLogger(log);
}

public void testLogOnlyOneTimePerClass () {
Kryo kryo = new Kryo();
kryo.setRegistrationRequired(false);
kryo.setWarnUnregisteredClasses(true);

write(kryo, new UnregisteredClass());
assertEquals(1, log.messages.size());

write(kryo, new UnregisteredClass());
assertEquals(1, log.messages.size());

write(kryo, new UnregisteredClass2());
assertEquals(2, log.messages.size());

write(kryo, new UnregisteredClass2());
assertEquals(2, log.messages.size());
}

public void testDontLogIfNotRequired () {
Kryo kryo = new Kryo();
kryo.setRegistrationRequired(false);
kryo.setWarnUnregisteredClasses(false);

write(kryo, new UnregisteredClass());
assertEquals(0, log.messages.size());

write(kryo, new UnregisteredClass2());
assertEquals(0, log.messages.size());
}

public void testDontLogClassIsRegistered () {
Kryo kryo = new Kryo();
kryo.setRegistrationRequired(false);
kryo.setWarnUnregisteredClasses(true);
kryo.register(RegisteredClass.class);

write(kryo, new RegisteredClass());
assertEquals(0, log.messages.size());
}

public void testLogShouldBeWarn () {
Kryo kryo = new Kryo();
kryo.setRegistrationRequired(false);
kryo.setWarnUnregisteredClasses(true);

write(kryo, new UnregisteredClass());
assertEquals(Log.LEVEL_WARN, log.levels.get(0).intValue());
}

public void testLogMessageShouldContainsClassName () {
Kryo kryo = new Kryo();
kryo.setRegistrationRequired(false);
kryo.setWarnUnregisteredClasses(true);

write(kryo, new UnregisteredClass());
assertTrue(log.messages.get(0).contains(UnregisteredClass.class.getName()));
}

public void write(Kryo kryo, Object object) {
StreamFactory sf = new StreamFactory() {
public Output createOutput(OutputStream os) {
return new UnsafeMemoryOutput(os);
}
public Output createOutput(OutputStream os, int size) {
return new UnsafeMemoryOutput(os, size);
}
public Output createOutput(int size, int limit) {
return new UnsafeMemoryOutput(size, limit);
}
public Input createInput(InputStream os, int size) {
return new UnsafeMemoryInput(os, size);
}
public Input createInput(byte[] buffer) {
return new UnsafeMemoryInput(buffer);
}
};
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
Output output = sf.createOutput(outStream, 4096);
kryo.writeClassAndObject(output, object);
output.flush();
}

class LoggerStub extends Logger {

public List<Integer> levels = new ArrayList();
public List<String> messages = new ArrayList();

@Override
public void log (int level, String category, String message, Throwable ex) {
levels.add(level);
messages.add(message);
}
}
}

class UnregisteredClass {
public UnregisteredClass() {}
}
class UnregisteredClass2 {
public UnregisteredClass2() {}
}
class RegisteredClass {
public RegisteredClass() {}
}

0 comments on commit cf253eb

Please sign in to comment.