8202056: Expand serial warning to check for bad overloads of serial-related methods and ineffectual fields
8160675: Issue lint warning for non-serializable non-transient instance fields in serializable type Reviewed-by: erikj, sspitsyn, jlahoda, vromero, rriggs, smarks
This commit is contained in:
parent
4e9dd4bddb
commit
6a466fe7ae
src
jdk.compiler/share/classes/com/sun/tools/javac
jdk.internal.opt/share/classes/jdk/internal/joptsimple
jdk.jdeps/share/classes/com/sun/tools
test/langtools/tools/javac
diags/examples
ImproperSPF.javaImproperSVUID.javaIneffectualSerialEnum.javaIneffectualSerialExtern.javaIneffectualSerialRecord.javaSerialInterfaceMethodsAndFields.javaSerialMissingNoArgCtor.javaSerialNonPrivateMethod.java
warnings/Serial
CtorAccess.javaCtorAccess.outDeepNestingSuppression.javaDeepNestingSuppression.outEnumSerial.javaEnumSerial.outExtern.javaExtern.outImproperReturnTypes.javaImproperReturnTypes.outImproperSerialPF.javaImproperSerialPF.outInstanceField.javaInstanceField.outInterfaceFields.javaInterfaceFields.outInterfaceNonPrivateMethods.javaInterfaceNonPrivateMethods.outRecordSerial.javaRecordSerial.outSerialMethodArity.javaSerialMethodArity.outSerialMethodMods.javaSerialMethodMods.outSerialMethodThrows.javaSerialMethodThrows.out
@ -224,6 +224,14 @@ public class Symtab {
|
||||
public final Type valueBasedType;
|
||||
public final Type valueBasedInternalType;
|
||||
|
||||
// For serialization lint checking
|
||||
public final Type objectStreamFieldType;
|
||||
public final Type objectInputStreamType;
|
||||
public final Type objectOutputStreamType;
|
||||
public final Type ioExceptionType;
|
||||
public final Type objectStreamExceptionType;
|
||||
public final Type externalizableType;
|
||||
|
||||
/** The symbol representing the length field of an array.
|
||||
*/
|
||||
public final VarSymbol lengthVar;
|
||||
@ -590,6 +598,13 @@ public class Symtab {
|
||||
switchBootstrapsType = enterClass("java.lang.runtime.SwitchBootstraps");
|
||||
valueBasedType = enterClass("jdk.internal.ValueBased");
|
||||
valueBasedInternalType = enterSyntheticAnnotation("jdk.internal.ValueBased+Annotation");
|
||||
// For serialization lint checking
|
||||
objectStreamFieldType = enterClass("java.io.ObjectStreamField");
|
||||
objectInputStreamType = enterClass("java.io.ObjectInputStream");
|
||||
objectOutputStreamType = enterClass("java.io.ObjectOutputStream");
|
||||
ioExceptionType = enterClass("java.io.IOException");
|
||||
objectStreamExceptionType = enterClass("java.io.ObjectStreamException");
|
||||
externalizableType = enterClass("java.io.Externalizable");
|
||||
|
||||
synthesizeEmptyInterfaceIfMissing(autoCloseableType);
|
||||
synthesizeEmptyInterfaceIfMissing(cloneableType);
|
||||
|
@ -2955,7 +2955,7 @@ public class Attr extends JCTree.Visitor {
|
||||
}
|
||||
|
||||
if (resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK &&
|
||||
isSerializable(clazztype)) {
|
||||
rs.isSerializable(clazztype)) {
|
||||
localEnv.info.isSerializable = true;
|
||||
}
|
||||
|
||||
@ -3080,7 +3080,7 @@ public class Attr extends JCTree.Visitor {
|
||||
boolean needsRecovery =
|
||||
resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK;
|
||||
try {
|
||||
if (needsRecovery && isSerializable(pt())) {
|
||||
if (needsRecovery && rs.isSerializable(pt())) {
|
||||
localEnv.info.isSerializable = true;
|
||||
localEnv.info.isSerializableLambda = true;
|
||||
}
|
||||
@ -3581,7 +3581,7 @@ public class Attr extends JCTree.Visitor {
|
||||
|
||||
boolean isTargetSerializable =
|
||||
resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK &&
|
||||
isSerializable(pt());
|
||||
rs.isSerializable(pt());
|
||||
TargetInfo targetInfo = getTargetInfo(that, resultInfo, null);
|
||||
Type currentTarget = targetInfo.target;
|
||||
Type desc = targetInfo.descriptor;
|
||||
@ -5366,7 +5366,7 @@ public class Attr extends JCTree.Visitor {
|
||||
log.error(env.tree.pos(), Errors.EnumTypesNotExtensible);
|
||||
}
|
||||
|
||||
if (isSerializable(c.type)) {
|
||||
if (rs.isSerializable(c.type)) {
|
||||
env.info.isSerializable = true;
|
||||
}
|
||||
|
||||
@ -5501,12 +5501,12 @@ public class Attr extends JCTree.Visitor {
|
||||
// Check for cycles among annotation elements.
|
||||
chk.checkNonCyclicElements(tree);
|
||||
|
||||
// Check for proper use of serialVersionUID
|
||||
// Check for proper use of serialVersionUID and other
|
||||
// serialization-related fields and methods
|
||||
if (env.info.lint.isEnabled(LintCategory.SERIAL)
|
||||
&& isSerializable(c.type)
|
||||
&& (c.flags() & (Flags.ENUM | Flags.INTERFACE)) == 0
|
||||
&& rs.isSerializable(c.type)
|
||||
&& !c.isAnonymous()) {
|
||||
checkSerialVersionUID(tree, c, env);
|
||||
chk.checkSerialStructure(tree, c);
|
||||
}
|
||||
if (allowTypeAnnos) {
|
||||
// Correctly organize the positions of the type annotations
|
||||
@ -5527,59 +5527,6 @@ public class Attr extends JCTree.Visitor {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** check if a type is a subtype of Serializable, if that is available. */
|
||||
boolean isSerializable(Type t) {
|
||||
try {
|
||||
syms.serializableType.complete();
|
||||
}
|
||||
catch (CompletionFailure e) {
|
||||
return false;
|
||||
}
|
||||
return types.isSubtype(t, syms.serializableType);
|
||||
}
|
||||
|
||||
/** Check that an appropriate serialVersionUID member is defined. */
|
||||
private void checkSerialVersionUID(JCClassDecl tree, ClassSymbol c, Env<AttrContext> env) {
|
||||
|
||||
// check for presence of serialVersionUID
|
||||
VarSymbol svuid = null;
|
||||
for (Symbol sym : c.members().getSymbolsByName(names.serialVersionUID)) {
|
||||
if (sym.kind == VAR) {
|
||||
svuid = (VarSymbol)sym;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (svuid == null) {
|
||||
if (!c.isRecord())
|
||||
log.warning(LintCategory.SERIAL, tree.pos(), Warnings.MissingSVUID(c));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if @SuppressWarnings("serial") is an annotation of serialVersionUID.
|
||||
// See JDK-8231622 for more information.
|
||||
Lint lint = env.info.lint.augment(svuid);
|
||||
if (lint.isSuppressed(LintCategory.SERIAL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check that it is static final
|
||||
if ((svuid.flags() & (STATIC | FINAL)) !=
|
||||
(STATIC | FINAL))
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(svuid, tree), Warnings.ImproperSVUID(c));
|
||||
|
||||
// check that it is long
|
||||
else if (!svuid.type.hasTag(LONG))
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(svuid, tree), Warnings.LongSVUID(c));
|
||||
|
||||
// check constant
|
||||
else if (svuid.getConstValue() == null)
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(svuid, tree), Warnings.ConstantSVUID(c));
|
||||
}
|
||||
|
||||
private Type capture(Type type) {
|
||||
return types.capture(type);
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
package com.sun.tools.javac.comp;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@ -71,6 +72,13 @@ import static com.sun.tools.javac.code.TypeTag.*;
|
||||
import static com.sun.tools.javac.code.TypeTag.WILDCARD;
|
||||
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.*;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.util.ElementFilter;
|
||||
import javax.lang.model.util.ElementKindVisitor14;
|
||||
|
||||
/** Type checking helper class for the attribution phase.
|
||||
*
|
||||
@ -4342,4 +4350,693 @@ public class Check {
|
||||
wasNonEmptyFallThrough = c.stats.nonEmpty() && completesNormally;
|
||||
}
|
||||
}
|
||||
|
||||
/** check if a type is a subtype of Externalizable, if that is available. */
|
||||
boolean isExternalizable(Type t) {
|
||||
try {
|
||||
syms.externalizableType.complete();
|
||||
}
|
||||
catch (CompletionFailure e) {
|
||||
return false;
|
||||
}
|
||||
return types.isSubtype(t, syms.externalizableType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check structure of serialization declarations.
|
||||
*/
|
||||
public void checkSerialStructure(JCClassDecl tree, ClassSymbol c) {
|
||||
(new SerialTypeVisitor()).visit(c, tree);
|
||||
}
|
||||
|
||||
/**
|
||||
* This visitor will warn if a serialization-related field or
|
||||
* method is declared in a suspicious or incorrect way. In
|
||||
* particular, it will warn for cases where the runtime
|
||||
* serialization mechanism will silently ignore a mis-declared
|
||||
* entity.
|
||||
*
|
||||
* Distinguished serialization-related fields and methods:
|
||||
*
|
||||
* Methods:
|
||||
*
|
||||
* private void writeObject(ObjectOutputStream stream) throws IOException
|
||||
* ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException
|
||||
*
|
||||
* private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
|
||||
* private void readObjectNoData() throws ObjectStreamException
|
||||
* ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException
|
||||
*
|
||||
* Fields:
|
||||
*
|
||||
* private static final long serialVersionUID
|
||||
* private static final ObjectStreamField[] serialPersistentFields
|
||||
*
|
||||
* Externalizable: methods defined on the interface
|
||||
* public void writeExternal(ObjectOutput) throws IOException
|
||||
* public void readExternal(ObjectInput) throws IOException
|
||||
*/
|
||||
private class SerialTypeVisitor extends ElementKindVisitor14<Void, JCClassDecl> {
|
||||
SerialTypeVisitor() {
|
||||
this.lint = Check.this.lint;
|
||||
}
|
||||
|
||||
private static final Set<String> serialMethodNames =
|
||||
Set.of("writeObject", "writeReplace",
|
||||
"readObject", "readObjectNoData",
|
||||
"readResolve");
|
||||
|
||||
private static final Set<String> serialFieldNames =
|
||||
Set.of("serialVersionUID", "serialPersistentFields");
|
||||
|
||||
// Type of serialPersistentFields
|
||||
private final Type OSF_TYPE = new Type.ArrayType(syms.objectStreamFieldType, syms.arrayClass);
|
||||
|
||||
Lint lint;
|
||||
|
||||
@Override
|
||||
public Void defaultAction(Element e, JCClassDecl p) {
|
||||
throw new IllegalArgumentException(Objects.requireNonNullElse(e.toString(), ""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitType(TypeElement e, JCClassDecl p) {
|
||||
runUnderLint(e, p, (symbol, param) -> super.visitType(symbol, param));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitTypeAsClass(TypeElement e,
|
||||
JCClassDecl p) {
|
||||
// Anonymous classes filtered out by caller.
|
||||
|
||||
ClassSymbol c = (ClassSymbol)e;
|
||||
|
||||
checkCtorAccess(p, c);
|
||||
|
||||
// Check for missing serialVersionUID; check *not* done
|
||||
// for enums or records.
|
||||
VarSymbol svuidSym = null;
|
||||
for (Symbol sym : c.members().getSymbolsByName(names.serialVersionUID)) {
|
||||
if (sym.kind == VAR) {
|
||||
svuidSym = (VarSymbol)sym;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (svuidSym == null) {
|
||||
log.warning(LintCategory.SERIAL, p.pos(), Warnings.MissingSVUID(c));
|
||||
}
|
||||
|
||||
// Check for serialPersistentFields to gate checks for
|
||||
// non-serializable non-transient instance fields
|
||||
boolean serialPersistentFieldsPresent =
|
||||
c.members()
|
||||
.getSymbolsByName(names.serialPersistentFields, sym -> sym.kind == VAR)
|
||||
.iterator()
|
||||
.hasNext();
|
||||
|
||||
// Check declarations of serialization-related methods and
|
||||
// fields
|
||||
for(Symbol el : c.getEnclosedElements()) {
|
||||
runUnderLint(el, p, (enclosed, tree) -> {
|
||||
String name = null;
|
||||
switch(enclosed.getKind()) {
|
||||
case FIELD -> {
|
||||
if (!serialPersistentFieldsPresent) {
|
||||
var flags = enclosed.flags();
|
||||
if ( ((flags & TRANSIENT) == 0) &&
|
||||
((flags & STATIC) == 0)) {
|
||||
Type varType = enclosed.asType();
|
||||
if (!canBeSerialized(varType)) {
|
||||
// Note per JLS arrays are
|
||||
// serializable even if the
|
||||
// component type is not.
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(enclosed, tree),
|
||||
Warnings.NonSerializableInstanceField);
|
||||
} else if (varType.hasTag(ARRAY)) {
|
||||
ArrayType arrayType = (ArrayType)varType;
|
||||
Type elementType = arrayType.elemtype;
|
||||
while (elementType.hasTag(ARRAY)) {
|
||||
arrayType = (ArrayType)elementType;
|
||||
elementType = arrayType.elemtype;
|
||||
}
|
||||
if (!canBeSerialized(elementType)) {
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(enclosed, tree),
|
||||
Warnings.NonSerializableInstanceFieldArray(elementType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
name = enclosed.getSimpleName().toString();
|
||||
if (serialFieldNames.contains(name)) {
|
||||
VarSymbol field = (VarSymbol)enclosed;
|
||||
switch (name) {
|
||||
case "serialVersionUID" -> checkSerialVersionUID(tree, e, field);
|
||||
case "serialPersistentFields" -> checkSerialPersistentFields(tree, e, field);
|
||||
default -> throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Correctly checking the serialization-related
|
||||
// methods is subtle. For the methods declared to be
|
||||
// private or directly declared in the class, the
|
||||
// enclosed elements of the class can be checked in
|
||||
// turn. However, writeReplace and readResolve can be
|
||||
// declared in a superclass and inherited. Note that
|
||||
// the runtime lookup walks the superclass chain
|
||||
// looking for writeReplace/readResolve via
|
||||
// Class.getDeclaredMethod. This differs from calling
|
||||
// Elements.getAllMembers(TypeElement) as the latter
|
||||
// will also pull in default methods from
|
||||
// superinterfaces. In other words, the runtime checks
|
||||
// (which long predate default methods on interfaces)
|
||||
// do not admit the possibility of inheriting methods
|
||||
// this way, a difference from general inheritance.
|
||||
|
||||
// The current implementation just checks the enclosed
|
||||
// elements and does not directly check the inherited
|
||||
// methods. If all the types are being checked this is
|
||||
// less of a concern; however, there are cases that
|
||||
// could be missed. In particular, readResolve and
|
||||
// writeReplace could, in principle, by inherited from
|
||||
// a non-serializable superclass and thus not checked
|
||||
// even if compiled with a serializable child class.
|
||||
case METHOD -> {
|
||||
var method = (MethodSymbol)enclosed;
|
||||
name = method.getSimpleName().toString();
|
||||
if (serialMethodNames.contains(name)) {
|
||||
switch (name) {
|
||||
case "writeObject" -> checkWriteObject(tree, e, method);
|
||||
case "writeReplace" -> checkWriteReplace(tree,e, method);
|
||||
case "readObject" -> checkReadObject(tree,e, method);
|
||||
case "readObjectNoData" -> checkReadObjectNoData(tree, e, method);
|
||||
case "readResolve" -> checkReadResolve(tree, e, method);
|
||||
default -> throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean canBeSerialized(Type type) {
|
||||
return type.isPrimitive() || rs.isSerializable(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that Externalizable class needs a public no-arg
|
||||
* constructor.
|
||||
*
|
||||
* Check that a Serializable class has access to the no-arg
|
||||
* constructor of its first nonserializable superclass.
|
||||
*/
|
||||
private void checkCtorAccess(JCClassDecl tree, ClassSymbol c) {
|
||||
if (isExternalizable(c.type)) {
|
||||
for(var sym : c.getEnclosedElements()) {
|
||||
if (sym.isConstructor() &&
|
||||
((sym.flags() & PUBLIC) == PUBLIC)) {
|
||||
if (((MethodSymbol)sym).getParameters().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
log.warning(LintCategory.SERIAL, tree.pos(),
|
||||
Warnings.ExternalizableMissingPublicNoArgCtor);
|
||||
} else {
|
||||
// Approximate access to the no-arg constructor up in
|
||||
// the superclass chain by checking that the
|
||||
// constructor is not private. This may not handle
|
||||
// some cross-package situations correctly.
|
||||
Type superClass = c.getSuperclass();
|
||||
// java.lang.Object is *not* Serializable so this loop
|
||||
// should terminate.
|
||||
while (rs.isSerializable(superClass) ) {
|
||||
try {
|
||||
superClass = (Type)((TypeElement)(((DeclaredType)superClass)).asElement()).getSuperclass();
|
||||
} catch(ClassCastException cce) {
|
||||
return ; // Don't try to recover
|
||||
}
|
||||
}
|
||||
// Non-Serializable super class
|
||||
try {
|
||||
ClassSymbol supertype = ((ClassSymbol)(((DeclaredType)superClass).asElement()));
|
||||
for(var sym : supertype.getEnclosedElements()) {
|
||||
if (sym.isConstructor()) {
|
||||
MethodSymbol ctor = (MethodSymbol)sym;
|
||||
if (ctor.getParameters().isEmpty()) {
|
||||
if (((ctor.flags() & PRIVATE) == PRIVATE) ||
|
||||
// Handle nested classes and implicit this$0
|
||||
(supertype.getNestingKind() == NestingKind.MEMBER &&
|
||||
((supertype.flags() & STATIC) == 0)))
|
||||
log.warning(LintCategory.SERIAL, tree.pos(),
|
||||
Warnings.SerializableMissingAccessNoArgCtor(supertype.getQualifiedName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ClassCastException cce) {
|
||||
return ; // Don't try to recover
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkSerialVersionUID(JCClassDecl tree, Element e, VarSymbol svuid) {
|
||||
// To be effective, serialVersionUID must be marked static
|
||||
// and final, but private is recommended. But alas, in
|
||||
// practice there are many non-private serialVersionUID
|
||||
// fields.
|
||||
if ((svuid.flags() & (STATIC | FINAL)) !=
|
||||
(STATIC | FINAL)) {
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(svuid, tree),
|
||||
Warnings.ImproperSVUID((Symbol)e));
|
||||
}
|
||||
|
||||
// check svuid has type long
|
||||
if (!svuid.type.hasTag(LONG)) {
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(svuid, tree),
|
||||
Warnings.LongSVUID((Symbol)e));
|
||||
}
|
||||
|
||||
if (svuid.getConstValue() == null)
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(svuid, tree),
|
||||
Warnings.ConstantSVUID((Symbol)e));
|
||||
}
|
||||
|
||||
private void checkSerialPersistentFields(JCClassDecl tree, Element e, VarSymbol spf) {
|
||||
// To be effective, serialPersisentFields must be private, static, and final.
|
||||
if ((spf.flags() & (PRIVATE | STATIC | FINAL)) !=
|
||||
(PRIVATE | STATIC | FINAL)) {
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(spf, tree), Warnings.ImproperSPF);
|
||||
}
|
||||
|
||||
if (!types.isSameType(spf.type, OSF_TYPE)) {
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(spf, tree), Warnings.OSFArraySPF);
|
||||
}
|
||||
|
||||
if (isExternalizable((Type)(e.asType()))) {
|
||||
log.warning(LintCategory.SERIAL, tree.pos(),
|
||||
Warnings.IneffectualSerialFieldExternalizable);
|
||||
}
|
||||
|
||||
// Warn if serialPersistentFields is initialized to a
|
||||
// literal null.
|
||||
JCTree spfDecl = TreeInfo.declarationFor(spf, tree);
|
||||
if (spfDecl != null && spfDecl.getTag() == VARDEF) {
|
||||
JCVariableDecl variableDef = (JCVariableDecl) spfDecl;
|
||||
JCExpression initExpr = variableDef.init;
|
||||
if (initExpr != null && TreeInfo.isNull(initExpr)) {
|
||||
log.warning(LintCategory.SERIAL, initExpr.pos(),
|
||||
Warnings.SPFNullInit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkWriteObject(JCClassDecl tree, Element e, MethodSymbol method) {
|
||||
// The "synchronized" modifier is seen in the wild on
|
||||
// readObject and writeObject methods and is generally
|
||||
// innocuous.
|
||||
|
||||
// private void writeObject(ObjectOutputStream stream) throws IOException
|
||||
checkPrivateNonStaticMethod(tree, method);
|
||||
checkReturnType(tree, e, method, syms.voidType);
|
||||
checkOneArg(tree, e, method, syms.objectOutputStreamType);
|
||||
checkExceptions(tree, e, method, syms.ioExceptionType);
|
||||
checkExternalizable(tree, e, method);
|
||||
}
|
||||
|
||||
private void checkWriteReplace(JCClassDecl tree, Element e, MethodSymbol method) {
|
||||
// ANY-ACCESS-MODIFIER Object writeReplace() throws
|
||||
// ObjectStreamException
|
||||
|
||||
// Excluding abstract, could have a more complicated
|
||||
// rule based on abstract-ness of the class
|
||||
checkConcreteInstanceMethod(tree, e, method);
|
||||
checkReturnType(tree, e, method, syms.objectType);
|
||||
checkNoArgs(tree, e, method);
|
||||
checkExceptions(tree, e, method, syms.objectStreamExceptionType);
|
||||
}
|
||||
|
||||
private void checkReadObject(JCClassDecl tree, Element e, MethodSymbol method) {
|
||||
// The "synchronized" modifier is seen in the wild on
|
||||
// readObject and writeObject methods and is generally
|
||||
// innocuous.
|
||||
|
||||
// private void readObject(ObjectInputStream stream)
|
||||
// throws IOException, ClassNotFoundException
|
||||
checkPrivateNonStaticMethod(tree, method);
|
||||
checkReturnType(tree, e, method, syms.voidType);
|
||||
checkOneArg(tree, e, method, syms.objectInputStreamType);
|
||||
checkExceptions(tree, e, method, syms.ioExceptionType, syms.classNotFoundExceptionType);
|
||||
checkExternalizable(tree, e, method);
|
||||
}
|
||||
|
||||
private void checkReadObjectNoData(JCClassDecl tree, Element e, MethodSymbol method) {
|
||||
// private void readObjectNoData() throws ObjectStreamException
|
||||
checkPrivateNonStaticMethod(tree, method);
|
||||
checkReturnType(tree, e, method, syms.voidType);
|
||||
checkNoArgs(tree, e, method);
|
||||
checkExceptions(tree, e, method, syms.objectStreamExceptionType);
|
||||
checkExternalizable(tree, e, method);
|
||||
}
|
||||
|
||||
private void checkReadResolve(JCClassDecl tree, Element e, MethodSymbol method) {
|
||||
// ANY-ACCESS-MODIFIER Object readResolve()
|
||||
// throws ObjectStreamException
|
||||
|
||||
// Excluding abstract, could have a more complicated
|
||||
// rule based on abstract-ness of the class
|
||||
checkConcreteInstanceMethod(tree, e, method);
|
||||
checkReturnType(tree,e, method, syms.objectType);
|
||||
checkNoArgs(tree, e, method);
|
||||
checkExceptions(tree, e, method, syms.objectStreamExceptionType);
|
||||
}
|
||||
|
||||
void checkPrivateNonStaticMethod(JCClassDecl tree, MethodSymbol method) {
|
||||
var flags = method.flags();
|
||||
if ((flags & PRIVATE) == 0) {
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(method, tree),
|
||||
Warnings.SerialMethodNotPrivate(method.getSimpleName()));
|
||||
}
|
||||
|
||||
if ((flags & STATIC) != 0) {
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(method, tree),
|
||||
Warnings.SerialMethodStatic(method.getSimpleName()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Per section 1.12 "Serialization of Enum Constants" of
|
||||
* the serialization specification, due to the special
|
||||
* serialization handling of enums, any writeObject,
|
||||
* readObject, writeReplace, and readResolve methods are
|
||||
* ignored as are serialPersistentFields and
|
||||
* serialVersionUID fields.
|
||||
*/
|
||||
@Override
|
||||
public Void visitTypeAsEnum(TypeElement e,
|
||||
JCClassDecl p) {
|
||||
for(Element el : e.getEnclosedElements()) {
|
||||
runUnderLint(el, p, (enclosed, tree) -> {
|
||||
String name = enclosed.getSimpleName().toString();
|
||||
switch(enclosed.getKind()) {
|
||||
case FIELD -> {
|
||||
if (serialFieldNames.contains(name)) {
|
||||
log.warning(LintCategory.SERIAL, tree.pos(),
|
||||
Warnings.IneffectualSerialFieldEnum(name));
|
||||
}
|
||||
}
|
||||
|
||||
case METHOD -> {
|
||||
if (serialMethodNames.contains(name)) {
|
||||
log.warning(LintCategory.SERIAL, tree.pos(),
|
||||
Warnings.IneffectualSerialMethodEnum(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Most serialization-related fields and methods on interfaces
|
||||
* are ineffectual or problematic.
|
||||
*/
|
||||
@Override
|
||||
public Void visitTypeAsInterface(TypeElement e,
|
||||
JCClassDecl p) {
|
||||
for(Element el : e.getEnclosedElements()) {
|
||||
runUnderLint(el, p, (enclosed, tree) -> {
|
||||
String name = null;
|
||||
switch(enclosed.getKind()) {
|
||||
case FIELD -> {
|
||||
var field = (VarSymbol)enclosed;
|
||||
name = field.getSimpleName().toString();
|
||||
switch(name) {
|
||||
case "serialPersistentFields" -> {
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(field, tree),
|
||||
Warnings.IneffectualSerialFieldInterface);
|
||||
}
|
||||
|
||||
case "serialVersionUID" -> {
|
||||
checkSerialVersionUID(tree, e, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case METHOD -> {
|
||||
var method = (MethodSymbol)enclosed;
|
||||
name = enclosed.getSimpleName().toString();
|
||||
if (serialMethodNames.contains(name)) {
|
||||
switch (name) {
|
||||
case
|
||||
"readObject",
|
||||
"readObjectNoData",
|
||||
"writeObject" -> checkPrivateMethod(tree, e, method);
|
||||
|
||||
case
|
||||
"writeReplace",
|
||||
"readResolve" -> checkDefaultIneffective(tree, e, method);
|
||||
|
||||
default -> throw new AssertionError();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void checkPrivateMethod(JCClassDecl tree,
|
||||
Element e,
|
||||
MethodSymbol method) {
|
||||
if ((method.flags() & PRIVATE) == 0) {
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(method, tree),
|
||||
Warnings.NonPrivateMethodWeakerAccess);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDefaultIneffective(JCClassDecl tree,
|
||||
Element e,
|
||||
MethodSymbol method) {
|
||||
if ((method.flags() & DEFAULT) == DEFAULT) {
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(method, tree),
|
||||
Warnings.DefaultIneffective);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitTypeAsAnnotationType(TypeElement e,
|
||||
JCClassDecl p) {
|
||||
// Per the JLS, annotation types are not serializeable
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* From the Java Object Serialization Specification, 1.13
|
||||
* Serialization of Records:
|
||||
*
|
||||
* "The process by which record objects are serialized or
|
||||
* externalized cannot be customized; any class-specific
|
||||
* writeObject, readObject, readObjectNoData, writeExternal,
|
||||
* and readExternal methods defined by record classes are
|
||||
* ignored during serialization and deserialization. However,
|
||||
* a substitute object to be serialized or a designate
|
||||
* replacement may be specified, by the writeReplace and
|
||||
* readResolve methods, respectively. Any
|
||||
* serialPersistentFields field declaration is
|
||||
* ignored. Documenting serializable fields and data for
|
||||
* record classes is unnecessary, since there is no variation
|
||||
* in the serial form, other than whether a substitute or
|
||||
* replacement object is used. The serialVersionUID of a
|
||||
* record class is 0L unless explicitly declared. The
|
||||
* requirement for matching serialVersionUID values is waived
|
||||
* for record classes."
|
||||
*/
|
||||
@Override
|
||||
public Void visitTypeAsRecord(TypeElement e,
|
||||
JCClassDecl p) {
|
||||
for(Element el : e.getEnclosedElements()) {
|
||||
runUnderLint(el, p, (enclosed, tree) -> {
|
||||
String name = enclosed.getSimpleName().toString();
|
||||
switch(enclosed.getKind()) {
|
||||
case FIELD -> {
|
||||
switch(name) {
|
||||
case "serialPersistentFields" -> {
|
||||
log.warning(LintCategory.SERIAL, tree.pos(),
|
||||
Warnings.IneffectualSerialFieldRecord);
|
||||
}
|
||||
|
||||
case "serialVersionUID" -> {
|
||||
// Could generate additional warning that
|
||||
// svuid value is not checked to match for
|
||||
// records.
|
||||
checkSerialVersionUID(tree, e, (VarSymbol)enclosed);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
case METHOD -> {
|
||||
var method = (MethodSymbol)enclosed;
|
||||
switch(name) {
|
||||
case "writeReplace" -> checkWriteReplace(tree, e, method);
|
||||
case "readResolve" -> checkReadResolve(tree, e, method);
|
||||
default -> {
|
||||
if (serialMethodNames.contains(name)) {
|
||||
log.warning(LintCategory.SERIAL, tree.pos(),
|
||||
Warnings.IneffectualSerialMethodRecord(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void checkConcreteInstanceMethod(JCClassDecl tree,
|
||||
Element enclosing,
|
||||
MethodSymbol method) {
|
||||
if ((method.flags() & (STATIC | ABSTRACT)) != 0) {
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(method, tree),
|
||||
Warnings.SerialConcreteInstanceMethod(method.getSimpleName()));
|
||||
}
|
||||
}
|
||||
|
||||
private void checkReturnType(JCClassDecl tree,
|
||||
Element enclosing,
|
||||
MethodSymbol method,
|
||||
Type expectedReturnType) {
|
||||
// Note: there may be complications checking writeReplace
|
||||
// and readResolve since they return Object and could, in
|
||||
// principle, have covariant overrides and any synthetic
|
||||
// bridge method would not be represented here for
|
||||
// checking.
|
||||
Type rtype = method.getReturnType();
|
||||
if (!types.isSameType(expectedReturnType, rtype)) {
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(method, tree),
|
||||
Warnings.SerialMethodUnexpectedReturnType(method.getSimpleName(),
|
||||
rtype, expectedReturnType));
|
||||
}
|
||||
}
|
||||
|
||||
private void checkOneArg(JCClassDecl tree,
|
||||
Element enclosing,
|
||||
MethodSymbol method,
|
||||
Type expectedType) {
|
||||
String name = method.getSimpleName().toString();
|
||||
|
||||
var parameters= method.getParameters();
|
||||
|
||||
if (parameters.size() != 1) {
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(method, tree),
|
||||
Warnings.SerialMethodOneArg(method.getSimpleName(), parameters.size()));
|
||||
return;
|
||||
}
|
||||
|
||||
Type parameterType = parameters.get(0).asType();
|
||||
if (!types.isSameType(parameterType, expectedType)) {
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(method, tree),
|
||||
Warnings.SerialMethodParameterType(method.getSimpleName(),
|
||||
expectedType,
|
||||
parameterType));
|
||||
}
|
||||
}
|
||||
|
||||
private void checkNoArgs(JCClassDecl tree, Element enclosing, MethodSymbol method) {
|
||||
var parameters = method.getParameters();
|
||||
if (!parameters.isEmpty()) {
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(parameters.get(0), tree),
|
||||
Warnings.SerialMethodNoArgs(method.getSimpleName()));
|
||||
}
|
||||
}
|
||||
|
||||
private void checkExternalizable(JCClassDecl tree, Element enclosing, MethodSymbol method) {
|
||||
// If the enclosing class is externalizable, warn for the method
|
||||
if (isExternalizable((Type)enclosing.asType())) {
|
||||
log.warning(LintCategory.SERIAL, tree.pos(),
|
||||
Warnings.IneffectualSerialMethodExternalizable(method.getSimpleName()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private void checkExceptions(JCClassDecl tree,
|
||||
Element enclosing,
|
||||
MethodSymbol method,
|
||||
Type... declaredExceptions) {
|
||||
for (Type thrownType: method.getThrownTypes()) {
|
||||
// For each exception in the throws clause of the
|
||||
// method, if not an Error and not a RuntimeException,
|
||||
// check if the exception is a subtype of a declared
|
||||
// exception from the throws clause of the
|
||||
// serialization method in question.
|
||||
if (types.isSubtype(thrownType, syms.runtimeExceptionType) ||
|
||||
types.isSubtype(thrownType, syms.errorType) ) {
|
||||
continue;
|
||||
} else {
|
||||
boolean declared = false;
|
||||
for (Type declaredException : declaredExceptions) {
|
||||
if (types.isSubtype(thrownType, declaredException)) {
|
||||
declared = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!declared) {
|
||||
log.warning(LintCategory.SERIAL,
|
||||
TreeInfo.diagnosticPositionFor(method, tree),
|
||||
Warnings.SerialMethodUnexpectedException(method.getSimpleName(),
|
||||
thrownType));
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private <E extends Element> Void runUnderLint(E symbol, JCClassDecl p, BiConsumer<E, JCClassDecl> task) {
|
||||
Lint prevLint = lint;
|
||||
try {
|
||||
lint = lint.augment((Symbol) symbol);
|
||||
|
||||
if (lint.isEnabled(LintCategory.SERIAL)) {
|
||||
task.accept(symbol, p);
|
||||
}
|
||||
|
||||
return null;
|
||||
} finally {
|
||||
lint = prevLint;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3908,6 +3908,17 @@ public class Resolve {
|
||||
}
|
||||
}
|
||||
|
||||
/** check if a type is a subtype of Serializable, if that is available.*/
|
||||
boolean isSerializable(Type t) {
|
||||
try {
|
||||
syms.serializableType.complete();
|
||||
}
|
||||
catch (CompletionFailure e) {
|
||||
return false;
|
||||
}
|
||||
return types.isSubtype(t, syms.serializableType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Root class for resolution errors. Subclass of ResolveError
|
||||
* represent a different kinds of resolution error - as such they must
|
||||
|
@ -1846,6 +1846,14 @@ compiler.warn.illegal.char.for.encoding=\
|
||||
compiler.warn.improper.SVUID=\
|
||||
serialVersionUID must be declared static final in class {0}
|
||||
|
||||
compiler.warn.improper.SPF=\
|
||||
serialPersistentFields must be declared private static final to be effective
|
||||
|
||||
compiler.warn.SPF.null.init=\
|
||||
serialPersistentFields ineffective if initialized to null.\n\
|
||||
Initialize to an empty array to indicate no fields
|
||||
|
||||
|
||||
# 0: type, 1: type
|
||||
compiler.warn.inexact.non-varargs.call=\
|
||||
non-varargs call of varargs method with inexact argument type for last parameter;\n\
|
||||
@ -1866,10 +1874,92 @@ compiler.warn.unreachable.catch.1=\
|
||||
compiler.warn.long.SVUID=\
|
||||
serialVersionUID must be of type long in class {0}
|
||||
|
||||
compiler.warn.OSF.array.SPF=\
|
||||
serialPersistentFields must be of type java.io.ObjectStreamField[] to be effective
|
||||
|
||||
# 0: symbol
|
||||
compiler.warn.missing.SVUID=\
|
||||
serializable class {0} has no definition of serialVersionUID
|
||||
|
||||
# 0: name
|
||||
compiler.warn.serializable.missing.access.no.arg.ctor=\
|
||||
cannot access a no-arg constructor in first non-serializable superclass {0}
|
||||
|
||||
# 0: name
|
||||
compiler.warn.serial.method.not.private=\
|
||||
serialization-related method {0} not declared private
|
||||
|
||||
# 0: name
|
||||
compiler.warn.serial.concrete.instance.method=\
|
||||
serialization-related method {0} must be a concrete instance method to be effective, neither abstract nor static
|
||||
|
||||
# 0: name
|
||||
compiler.warn.serial.method.static=\
|
||||
serialization-related method {0} declared static; must instead be an instance method to be effective
|
||||
|
||||
# 0: name
|
||||
compiler.warn.serial.method.no.args=\
|
||||
to be effective serialization-related method {0} must have no parameters
|
||||
|
||||
# 0: name, 1: number
|
||||
compiler.warn.serial.method.one.arg=\
|
||||
to be effective serialization-related method {0} must have exactly one parameter rather than {1} parameters
|
||||
|
||||
# 0: name, 1: type, 2: type
|
||||
compiler.warn.serial.method.parameter.type=\
|
||||
sole parameter of serialization-related method {0} must have type {1} to be effective rather than type {2}
|
||||
|
||||
# 0: name, 1: type, 2: type
|
||||
compiler.warn.serial.method.unexpected.return.type=\
|
||||
serialization-related method {0} declared with a return type of {1} rather than expected type {2}.\n\
|
||||
As declared, the method will be ineffective for serialization
|
||||
|
||||
# 0: name, 1: type
|
||||
compiler.warn.serial.method.unexpected.exception=\
|
||||
serialization-related method {0} declared to throw an unexpected type {1}
|
||||
|
||||
compiler.warn.ineffectual.serial.field.interface=\
|
||||
serialPersistentFields is not effective in an interface
|
||||
|
||||
# 0: string
|
||||
compiler.warn.ineffectual.serial.field.enum=\
|
||||
serialization-related field {0} is not effective in an enum class
|
||||
|
||||
# 0: string
|
||||
compiler.warn.ineffectual.serial.method.enum=\
|
||||
serialization-related method {0} is not effective in an enum class
|
||||
|
||||
compiler.warn.ineffectual.serial.field.record=\
|
||||
serialPersistentFields is not effective in a record class
|
||||
|
||||
# 0: string
|
||||
compiler.warn.ineffectual.serial.method.record=\
|
||||
serialization-related method {0} is not effective in a record class
|
||||
|
||||
# 0: name
|
||||
compiler.warn.ineffectual.serial.method.externalizable=\
|
||||
serialization-related method {0} is not effective in an Externalizable class
|
||||
|
||||
compiler.warn.ineffectual.serial.field.externalizable=\
|
||||
serialPersistentFields is not effective in an Externalizable class
|
||||
|
||||
compiler.warn.externalizable.missing.public.no.arg.ctor=\
|
||||
an Externalizable class needs a public no-arg constructor
|
||||
|
||||
compiler.warn.non.serializable.instance.field=\
|
||||
non-transient instance field of a serializable class declared with a non-serializable type
|
||||
|
||||
# 0: type
|
||||
compiler.warn.non.serializable.instance.field.array=\
|
||||
non-transient instance field of a serializable class declared with an array having a non-serializable base component type {0}
|
||||
|
||||
compiler.warn.non.private.method.weaker.access=\
|
||||
serialization-related method declared non-private in an interface will prevent\n\
|
||||
classes implementing the interface from declaring the method as private
|
||||
|
||||
compiler.warn.default.ineffective=\
|
||||
serialization-related default method from an interface will not be run by serialization for an implementing class
|
||||
|
||||
# 0: symbol, 1: symbol, 2: symbol, 3: symbol
|
||||
compiler.warn.potentially.ambiguous.overload=\
|
||||
{0} in {1} is potentially ambiguous with {2} in {3}
|
||||
|
@ -240,8 +240,8 @@ javac.opt.Xlint.desc.requires-transitive-automatic=\
|
||||
Warn about automatic modules in requires transitive.
|
||||
|
||||
javac.opt.Xlint.desc.serial=\
|
||||
Warn about Serializable classes that do not provide a serial version ID. \n\
|
||||
\ Also warn about access to non-public members from a serializable element.
|
||||
Warn about Serializable classes that do not have a serialVersionUID field. \n\
|
||||
\ Also warn about other suspect declarations in Serializable and Externalizable classes and interfaces.
|
||||
|
||||
javac.opt.Xlint.desc.static=\
|
||||
Warn about accessing a static member using an instance.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -76,6 +76,7 @@ import static jdk.internal.joptsimple.internal.Messages.*;
|
||||
public abstract class OptionException extends RuntimeException {
|
||||
private static final long serialVersionUID = -1L;
|
||||
|
||||
@SuppressWarnings("serial") // Type of field is not Serializable
|
||||
private final List<String> options = new ArrayList<>();
|
||||
|
||||
protected OptionException( List<String> options ) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -100,6 +100,7 @@ public class ConstantPool {
|
||||
return "value not found: " + value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial") // Type of field is not Serializable
|
||||
public final Object value;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -43,5 +43,6 @@ public class InternalError extends Error {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial") // Array component type is not Serializable
|
||||
public final Object[] args;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -93,6 +93,7 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
|
||||
}
|
||||
|
||||
final String key;
|
||||
@SuppressWarnings("serial") // Array component type is not Serializable
|
||||
final Object[] args;
|
||||
boolean showUsage;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -63,6 +63,7 @@ class JdepsTask {
|
||||
return this;
|
||||
}
|
||||
final String key;
|
||||
@SuppressWarnings("serial") // Array component type is not Serializable
|
||||
final Object[] args;
|
||||
boolean showUsage;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -34,6 +34,7 @@ package com.sun.tools.jdeps;
|
||||
class MultiReleaseException extends RuntimeException {
|
||||
private static final long serialVersionUID = 4474870142461654108L;
|
||||
private final String key;
|
||||
@SuppressWarnings("serial") // Array component type is not Serializable
|
||||
private final Object[] params;
|
||||
|
||||
/**
|
||||
|
38
test/langtools/tools/javac/diags/examples/ImproperSPF.java
Normal file
38
test/langtools/tools/javac/diags/examples/ImproperSPF.java
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.warn.improper.SPF
|
||||
// key: compiler.warn.OSF.array.SPF
|
||||
// key: compiler.warn.SPF.null.init
|
||||
|
||||
// options: -Xlint:serial
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
class ImproperSPF implements Serializable {
|
||||
// Proper declaration of serialPersistentFields is:
|
||||
// private static final ObjectStreamField[] serialPersistentFields = ...
|
||||
public /*instance*/ Object serialPersistentFields = null;
|
||||
|
||||
private static final long serialVersionUID = 42;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -22,6 +22,9 @@
|
||||
*/
|
||||
|
||||
// key: compiler.warn.improper.SVUID
|
||||
// key: compiler.warn.constant.SVUID
|
||||
// key: compiler.warn.long.SVUID
|
||||
|
||||
// options: -Xlint:serial
|
||||
|
||||
import java.io.Serializable;
|
||||
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.warn.ineffectual.serial.field.enum
|
||||
// key: compiler.warn.ineffectual.serial.method.enum
|
||||
|
||||
// options: -Xlint:serial
|
||||
|
||||
import java.io.*;
|
||||
|
||||
enum IneffectualSerialEnum implements Serializable {
|
||||
INSTANCE;
|
||||
|
||||
// The serialVersionUID field is ineffectual for enum classes.
|
||||
private static final long serialVersionUID = 42;
|
||||
|
||||
// The readObject method is ineffectual for enum classes.
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
return;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.warn.ineffectual.serial.method.externalizable
|
||||
// key: compiler.warn.ineffectual.serial.field.externalizable
|
||||
// key: compiler.warn.externalizable.missing.public.no.arg.ctor
|
||||
|
||||
// options: -Xlint:serial
|
||||
|
||||
import java.io.*;
|
||||
|
||||
class IneffectualSerialExtern implements Externalizable {
|
||||
private static final long serialVersionUID = 42;
|
||||
|
||||
// Must have a public no-arg constructor
|
||||
public IneffectualSerialExtern(int foo) {}
|
||||
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
return;
|
||||
}
|
||||
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
return;
|
||||
}
|
||||
|
||||
// ineffectual
|
||||
private static final ObjectStreamField[] serialPersistentFields = {};
|
||||
|
||||
// The readObject method is ineffectual for Externalizable classes.
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
return;
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.warn.ineffectual.serial.field.record
|
||||
// key: compiler.warn.ineffectual.serial.method.record
|
||||
|
||||
// options: -Xlint:serial
|
||||
|
||||
import java.io.*;
|
||||
|
||||
record IneffectualSerialRecord(int foo) implements Serializable {
|
||||
|
||||
// A serialPersistentFields is ineffectual for enum classes.
|
||||
private static final ObjectStreamField[] serialPersistentFields = {};
|
||||
|
||||
// The readObject method is ineffectual for record classes.
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
return;
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.warn.non.private.method.weaker.access
|
||||
// key: compiler.warn.default.ineffective
|
||||
// key: compiler.warn.ineffectual.serial.field.interface
|
||||
|
||||
// options: -Xlint:serial
|
||||
|
||||
import java.io.*;
|
||||
|
||||
interface SerialInterfaceMethodsAndFields extends Serializable {
|
||||
public static final ObjectStreamField[] serialPersistentFields = {};
|
||||
public void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException;
|
||||
public void readObjectNoData() throws ObjectStreamException;
|
||||
public void writeObject(ObjectOutputStream stream) throws IOException;
|
||||
|
||||
default public Object readResolve() throws ObjectStreamException {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.warn.serializable.missing.access.no.arg.ctor
|
||||
// key: compiler.warn.non.serializable.instance.field
|
||||
// key: compiler.warn.non.serializable.instance.field.array
|
||||
|
||||
// options: -Xlint:serial
|
||||
|
||||
import java.io.*;
|
||||
|
||||
class SerialMissingNoArgCtor {
|
||||
public SerialMissingNoArgCtor(int foo) {
|
||||
}
|
||||
|
||||
// Not accessible to SerialSubclass
|
||||
private SerialMissingNoArgCtor() {}
|
||||
|
||||
// SerialSubclass does not have access to a non-arg ctor in the
|
||||
// first non-serializable superclass in its superclass chain.
|
||||
static class SerialSubclass extends SerialMissingNoArgCtor
|
||||
implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 42;
|
||||
|
||||
// non-serializable non-transient instance field
|
||||
private Object datum = null;
|
||||
|
||||
// base component type of array is non-serializable
|
||||
private Object[] data = null;
|
||||
|
||||
public SerialSubclass() {
|
||||
super(1);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.warn.serial.method.not.private
|
||||
// key: compiler.warn.serial.method.static
|
||||
// key: compiler.warn.serial.method.unexpected.return.type
|
||||
// key: compiler.warn.serial.concrete.instance.method
|
||||
// key: compiler.warn.serial.method.one.arg
|
||||
// key: compiler.warn.serial.method.parameter.type
|
||||
// key: compiler.warn.serial.method.no.args
|
||||
// key: compiler.warn.serial.method.unexpected.exception
|
||||
|
||||
// options: -Xlint:serial
|
||||
|
||||
import java.io.*;
|
||||
|
||||
|
||||
abstract class SerialNonPrivateMethod implements Serializable {
|
||||
private static final long serialVersionUID = 42;
|
||||
|
||||
private static class CustomObjectOutputStream extends ObjectOutputStream {
|
||||
public CustomObjectOutputStream() throws IOException,
|
||||
SecurityException {}
|
||||
}
|
||||
|
||||
// Should be private and have a single argument of type
|
||||
// ObjectOutputStream
|
||||
void writeObject(CustomObjectOutputStream stream) throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
}
|
||||
|
||||
// Should be private non-static and have one argument
|
||||
private static void readObject(ObjectInputStream stream, int retries)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
}
|
||||
|
||||
// Should return void
|
||||
private int readObjectNoData() throws ObjectStreamException {
|
||||
return 42;
|
||||
}
|
||||
|
||||
// Should be concrete instance method
|
||||
public abstract Object writeReplace() throws ObjectStreamException;
|
||||
|
||||
// Should have no arguments and throw ObjectStreamException
|
||||
/*package*/ Object readResolve(int foo)
|
||||
throws ReflectiveOperationException { // Checked exception
|
||||
return null;
|
||||
}
|
||||
}
|
37
test/langtools/tools/javac/warnings/Serial/CtorAccess.java
Normal file
37
test/langtools/tools/javac/warnings/Serial/CtorAccess.java
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8202056
|
||||
* @compile/ref=CtorAccess.out -XDrawDiagnostics -Xlint:serial CtorAccess.java
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
class CtorAccess {
|
||||
public CtorAccess(int i) {}
|
||||
|
||||
// Cannot by accessed by SerialSubclass
|
||||
private CtorAccess(){}
|
||||
|
||||
static class SerialSubclass
|
||||
extends CtorAccess
|
||||
implements Serializable {
|
||||
private static final long serialVersionUID = 42;
|
||||
SerialSubclass() {
|
||||
super(42);
|
||||
}
|
||||
}
|
||||
|
||||
// *not* static
|
||||
class MemberSuper {
|
||||
// Implicit this$0 argument
|
||||
public MemberSuper() {}
|
||||
}
|
||||
|
||||
class SerialMemberSub
|
||||
extends MemberSuper
|
||||
implements Serializable {
|
||||
|
||||
SerialMemberSub(){super();}
|
||||
private static final long serialVersionUID = 42;
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
CtorAccess.java:15:12: compiler.warn.serializable.missing.access.no.arg.ctor: CtorAccess
|
||||
CtorAccess.java:30:5: compiler.warn.serializable.missing.access.no.arg.ctor: CtorAccess.MemberSuper
|
||||
2 warnings
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8202056
|
||||
* @compile/ref=DeepNestingSuppression.out -XDrawDiagnostics -Xlint:serial DeepNestingSuppression.java
|
||||
*/
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/*
|
||||
* Verify suppressing serial warnings works through several levels of
|
||||
* nested types.
|
||||
*/
|
||||
class DeepNestingSuppression {
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
static class SuppressedOuter {
|
||||
static class Intermediate {
|
||||
static class Inner implements Serializable {
|
||||
// warning for int rather than long svuid
|
||||
private static final int serialVersionUID = 42;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class Outer {
|
||||
static class Intermediate {
|
||||
static class Inner implements Serializable {
|
||||
// warning for int rather than long svuid
|
||||
private static final int serialVersionUID = 42;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
DeepNestingSuppression.java:29:42: compiler.warn.long.SVUID: DeepNestingSuppression.Outer.Intermediate.Inner
|
||||
1 warning
|
38
test/langtools/tools/javac/warnings/Serial/EnumSerial.java
Normal file
38
test/langtools/tools/javac/warnings/Serial/EnumSerial.java
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8202056
|
||||
* @compile/ref=EnumSerial.out -XDrawDiagnostics -Xlint:serial EnumSerial.java
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
enum EnumSerial implements Serializable {
|
||||
INSTANCE;
|
||||
|
||||
// Verify a warning is generated in an enum class for each of the
|
||||
// distinguished serial fields and methods.
|
||||
|
||||
private static final long serialVersionUID = 42;
|
||||
private static final ObjectStreamField[] serialPersistentFields = {};
|
||||
|
||||
private void writeObject(ObjectOutputStream stream) throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
}
|
||||
|
||||
private Object writeReplace() throws ObjectStreamException {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
}
|
||||
|
||||
private void readObjectNoData() throws ObjectStreamException {
|
||||
return;
|
||||
}
|
||||
|
||||
private Object readResolve() throws ObjectStreamException {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
EnumSerial.java:9:1: compiler.warn.ineffectual.serial.field.enum: serialVersionUID
|
||||
EnumSerial.java:9:1: compiler.warn.ineffectual.serial.field.enum: serialPersistentFields
|
||||
EnumSerial.java:9:1: compiler.warn.ineffectual.serial.method.enum: writeObject
|
||||
EnumSerial.java:9:1: compiler.warn.ineffectual.serial.method.enum: writeReplace
|
||||
EnumSerial.java:9:1: compiler.warn.ineffectual.serial.method.enum: readObject
|
||||
EnumSerial.java:9:1: compiler.warn.ineffectual.serial.method.enum: readObjectNoData
|
||||
EnumSerial.java:9:1: compiler.warn.ineffectual.serial.method.enum: readResolve
|
||||
7 warnings
|
51
test/langtools/tools/javac/warnings/Serial/Extern.java
Normal file
51
test/langtools/tools/javac/warnings/Serial/Extern.java
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8202056
|
||||
* @compile/ref=Extern.out -XDrawDiagnostics -Xlint:serial Extern.java
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
class Extern implements Externalizable {
|
||||
private static final long serialVersionUID = 42;
|
||||
|
||||
// No-arg constructor on an Externalizable class must be public
|
||||
protected Extern() {}
|
||||
|
||||
// ineffectual
|
||||
private static final ObjectStreamField[] serialPersistentFields = {};
|
||||
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
return;
|
||||
}
|
||||
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
return;
|
||||
}
|
||||
|
||||
// ineffectual
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
}
|
||||
|
||||
// ineffectual
|
||||
private void writeObject(ObjectOutputStream stream) throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
}
|
||||
|
||||
// ineffectual
|
||||
private void readObjectNoData() throws ObjectStreamException {
|
||||
return;
|
||||
}
|
||||
|
||||
// (possibly) effective
|
||||
private Object writeReplace() throws ObjectStreamException {
|
||||
return null;
|
||||
}
|
||||
|
||||
// (possibly) effective
|
||||
private Object readResolve() throws ObjectStreamException {
|
||||
return null;
|
||||
}
|
||||
}
|
6
test/langtools/tools/javac/warnings/Serial/Extern.out
Normal file
6
test/langtools/tools/javac/warnings/Serial/Extern.out
Normal file
@ -0,0 +1,6 @@
|
||||
Extern.java:9:1: compiler.warn.externalizable.missing.public.no.arg.ctor
|
||||
Extern.java:9:1: compiler.warn.ineffectual.serial.field.externalizable
|
||||
Extern.java:9:1: compiler.warn.ineffectual.serial.method.externalizable: readObject
|
||||
Extern.java:9:1: compiler.warn.ineffectual.serial.method.externalizable: writeObject
|
||||
Extern.java:9:1: compiler.warn.ineffectual.serial.method.externalizable: readObjectNoData
|
||||
5 warnings
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8202056
|
||||
* @compile/ref=ImproperReturnTypes.out -XDrawDiagnostics -Xlint:serial ImproperReturnTypes.java
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
class ImproperReturnTypes implements Serializable {
|
||||
private static final long serialVersionUID = 42;
|
||||
|
||||
/*
|
||||
* Serialization-related methods return either void or Object:
|
||||
*
|
||||
* private void writeObject(ObjectOutputStream stream) throws IOException
|
||||
* ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException
|
||||
*
|
||||
* private void readObject(ObjectInputStream stream)
|
||||
* throws IOException, ClassNotFoundException
|
||||
* private void readObjectNoData() throws ObjectStreamException
|
||||
* ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException
|
||||
*/
|
||||
|
||||
private int writeObject(ObjectOutputStream stream) throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int writeReplace() throws ObjectStreamException {
|
||||
return 1;
|
||||
}
|
||||
|
||||
private int readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
return 2;
|
||||
}
|
||||
|
||||
private int readObjectNoData() throws ObjectStreamException {
|
||||
return 3;
|
||||
}
|
||||
|
||||
private int readResolve() throws ObjectStreamException {
|
||||
return 4;
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
ImproperReturnTypes.java:24:17: compiler.warn.serial.method.unexpected.return.type: writeObject, int, void
|
||||
ImproperReturnTypes.java:29:17: compiler.warn.serial.method.unexpected.return.type: writeReplace, int, java.lang.Object
|
||||
ImproperReturnTypes.java:33:17: compiler.warn.serial.method.unexpected.return.type: readObject, int, void
|
||||
ImproperReturnTypes.java:39:17: compiler.warn.serial.method.unexpected.return.type: readObjectNoData, int, void
|
||||
ImproperReturnTypes.java:43:17: compiler.warn.serial.method.unexpected.return.type: readResolve, int, java.lang.Object
|
||||
5 warnings
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8202056
|
||||
* @compile/ref=ImproperSerialPF.out -XDrawDiagnostics -Xlint:serial ImproperSerialPF.java
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
class ImproperSerialPF implements Serializable {
|
||||
// Proper declaration of serialPersistentFields is:
|
||||
// private static final ObjectStreamField[] serialPersistentFields = ...
|
||||
public /*instance*/ Object serialPersistentFields = Boolean.TRUE;
|
||||
|
||||
private static final long serialVersionUID = 42;
|
||||
|
||||
static class LiteralNullSPF implements Serializable {
|
||||
private static final ObjectStreamField[] serialPersistentFields = null;
|
||||
|
||||
private static final long serialVersionUID = 42;
|
||||
}
|
||||
|
||||
// Casting obscures the simple syntactic null-check
|
||||
static class CastedNullSPF implements Serializable {
|
||||
private static final ObjectStreamField[] serialPersistentFields =
|
||||
(ObjectStreamField[])null;
|
||||
|
||||
private static final long serialVersionUID = 42;
|
||||
}
|
||||
|
||||
// Conditional obscures the simple syntactic null-check too
|
||||
static class ConditionalNullSPF implements Serializable {
|
||||
private static final ObjectStreamField[] serialPersistentFields =
|
||||
(true ? null : null);
|
||||
|
||||
private static final long serialVersionUID = 42;
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
ImproperSerialPF.java:17:75: compiler.warn.SPF.null.init
|
||||
ImproperSerialPF.java:12:32: compiler.warn.improper.SPF
|
||||
ImproperSerialPF.java:12:32: compiler.warn.OSF.array.SPF
|
||||
3 warnings
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8202056
|
||||
* @compile/ref=InstanceField.out -XDrawDiagnostics -Xlint:serial InstanceField.java
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
class IntanceField implements Serializable {
|
||||
private static final long serialVersionUID = 42;
|
||||
|
||||
// Non-transient instance fields in a serializable class w/o
|
||||
// serialPersistentFields defined should get warnings if the type
|
||||
// of the field cannot be serialized.
|
||||
|
||||
private Object foo;
|
||||
|
||||
private Object[] foos;
|
||||
|
||||
private Thread[][] ArrayOfArrayOfThreads;
|
||||
|
||||
// No warnings
|
||||
|
||||
private static Object bar;
|
||||
|
||||
private static Object[] bars;
|
||||
|
||||
private int baz;
|
||||
|
||||
private double[] quux;
|
||||
|
||||
static class NestedInstance implements Serializable {
|
||||
private static final long serialVersionUID = 24;
|
||||
|
||||
// Should disable instance field warnings
|
||||
private static final ObjectStreamField[] serialPersistentFields = {};
|
||||
|
||||
private Object foo;
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
InstanceField.java:16:20: compiler.warn.non.serializable.instance.field
|
||||
InstanceField.java:18:22: compiler.warn.non.serializable.instance.field.array: java.lang.Object
|
||||
InstanceField.java:20:24: compiler.warn.non.serializable.instance.field.array: java.lang.Thread
|
||||
3 warnings
|
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8202056
|
||||
* @compile/ref=InterfaceFields.out -XDrawDiagnostics -Xlint:serial InterfaceFields.java
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
interface InterfaceFields extends Serializable {
|
||||
public static final int serialVersionUID = 12345;
|
||||
|
||||
public static final ObjectStreamField[] serialPersistentFields = {};
|
||||
}
|
||||
|
@ -0,0 +1,3 @@
|
||||
InterfaceFields.java:10:29: compiler.warn.long.SVUID: InterfaceFields
|
||||
InterfaceFields.java:12:45: compiler.warn.ineffectual.serial.field.interface
|
||||
2 warnings
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8202056
|
||||
* @compile/ref=InterfaceNonPrivateMethods.out -XDrawDiagnostics -Xlint:serial InterfaceNonPrivateMethods.java
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
// Holder class
|
||||
class InterfaceNonPrivateMethods {
|
||||
|
||||
interface NonPrivateMethods extends Serializable {
|
||||
public void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException;
|
||||
public void readObjectNoData() throws ObjectStreamException;
|
||||
public void writeObject(ObjectOutputStream stream) throws IOException;
|
||||
|
||||
// Ineffective default methods; serialization only looks up
|
||||
// superclass chain
|
||||
public default Object writeReplace() throws ObjectStreamException {
|
||||
return null;
|
||||
}
|
||||
public default Object readResolve() throws ObjectStreamException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
interface NonPrivateMethodsDefaults extends Serializable {
|
||||
default public void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
return;
|
||||
}
|
||||
default public void readObjectNoData()
|
||||
throws ObjectStreamException {
|
||||
return;
|
||||
}
|
||||
default public void writeObject(ObjectOutputStream stream)
|
||||
throws IOException {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
InterfaceNonPrivateMethods.java:13:21: compiler.warn.non.private.method.weaker.access
|
||||
InterfaceNonPrivateMethods.java:15:21: compiler.warn.non.private.method.weaker.access
|
||||
InterfaceNonPrivateMethods.java:16:21: compiler.warn.non.private.method.weaker.access
|
||||
InterfaceNonPrivateMethods.java:20:31: compiler.warn.default.ineffective
|
||||
InterfaceNonPrivateMethods.java:23:31: compiler.warn.default.ineffective
|
||||
InterfaceNonPrivateMethods.java:29:29: compiler.warn.non.private.method.weaker.access
|
||||
InterfaceNonPrivateMethods.java:33:29: compiler.warn.non.private.method.weaker.access
|
||||
InterfaceNonPrivateMethods.java:37:29: compiler.warn.non.private.method.weaker.access
|
||||
8 warnings
|
44
test/langtools/tools/javac/warnings/Serial/RecordSerial.java
Normal file
44
test/langtools/tools/javac/warnings/Serial/RecordSerial.java
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8202056
|
||||
* @compile/ref=RecordSerial.out -XDrawDiagnostics -Xlint:serial RecordSerial.java
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
record RecordSerial(int foo) implements Serializable {
|
||||
// Verify a warning is generated in a record class for each of the
|
||||
// ineffectual serial fields and methods.
|
||||
|
||||
// partially effective
|
||||
private static final long serialVersionUID = 42;
|
||||
|
||||
// ineffectual
|
||||
private static final ObjectStreamField[] serialPersistentFields = {};
|
||||
|
||||
// ineffectual
|
||||
private void writeObject(ObjectOutputStream stream) throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
}
|
||||
|
||||
// (possibly) effective
|
||||
private Object writeReplace() throws ObjectStreamException {
|
||||
return null;
|
||||
}
|
||||
|
||||
// ineffectual
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
}
|
||||
|
||||
// ineffectual
|
||||
private void readObjectNoData() throws ObjectStreamException {
|
||||
return;
|
||||
}
|
||||
|
||||
// (possibly) effective
|
||||
private Object readResolve() throws ObjectStreamException {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
RecordSerial.java:9:1: compiler.warn.ineffectual.serial.field.record
|
||||
RecordSerial.java:9:1: compiler.warn.ineffectual.serial.method.record: writeObject
|
||||
RecordSerial.java:9:1: compiler.warn.ineffectual.serial.method.record: readObject
|
||||
RecordSerial.java:9:1: compiler.warn.ineffectual.serial.method.record: readObjectNoData
|
||||
4 warnings
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8202056
|
||||
* @compile/ref=SerialMethodArity.out -XDrawDiagnostics -Xlint:serial SerialMethodArity.java
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
class SerialMethodMods implements Serializable {
|
||||
private static final long serialVersionUID = 42;
|
||||
|
||||
private static class CustomObjectOutputStream extends ObjectOutputStream {
|
||||
public CustomObjectOutputStream() throws IOException,
|
||||
SecurityException {}
|
||||
}
|
||||
|
||||
// Should have a single parameter of exact type ObjectOutputStream
|
||||
private void writeObject(CustomObjectOutputStream stream) throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
}
|
||||
|
||||
// Should have a single parameter of exact type ObjectInputStream
|
||||
private void readObject(ObjectInputStream stream, int retries)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
}
|
||||
|
||||
// Should have no arguments
|
||||
private void readObjectNoData(int retries) throws ObjectStreamException {}
|
||||
|
||||
// Should have no arguments
|
||||
public Object writeReplace(int arg0, int arg1) throws ObjectStreamException {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Should have no arguments
|
||||
public Object readResolve(double foo, float bar) throws ObjectStreamException {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
SerialMethodArity.java:18:18: compiler.warn.serial.method.parameter.type: writeObject, java.io.ObjectOutputStream, SerialMethodMods.CustomObjectOutputStream
|
||||
SerialMethodArity.java:23:18: compiler.warn.serial.method.one.arg: readObject, 2
|
||||
SerialMethodArity.java:29:39: compiler.warn.serial.method.no.args: readObjectNoData
|
||||
SerialMethodArity.java:32:36: compiler.warn.serial.method.no.args: writeReplace
|
||||
SerialMethodArity.java:37:38: compiler.warn.serial.method.no.args: readResolve
|
||||
5 warnings
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8202056
|
||||
* @compile/ref=SerialMethodMods.out -XDrawDiagnostics -Xlint:serial SerialMethodMods.java
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
abstract class SerialMethodMods implements Serializable {
|
||||
private static final long serialVersionUID = 42;
|
||||
|
||||
// Should be private
|
||||
void writeObject(ObjectOutputStream stream) throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
}
|
||||
|
||||
// Should be private
|
||||
public void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
}
|
||||
|
||||
// Should be concrete instance method
|
||||
private static void readObjectNoData() throws ObjectStreamException {}
|
||||
|
||||
// Should be concrete instance method
|
||||
public abstract Object writeReplace() throws ObjectStreamException;
|
||||
|
||||
// Should be concrete instance method
|
||||
public static Object readResolve() throws ObjectStreamException {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
SerialMethodMods.java:13:10: compiler.warn.serial.method.not.private: writeObject
|
||||
SerialMethodMods.java:18:17: compiler.warn.serial.method.not.private: readObject
|
||||
SerialMethodMods.java:24:25: compiler.warn.serial.method.static: readObjectNoData
|
||||
SerialMethodMods.java:27:28: compiler.warn.serial.concrete.instance.method: writeReplace
|
||||
SerialMethodMods.java:30:26: compiler.warn.serial.concrete.instance.method: readResolve
|
||||
5 warnings
|
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8202056
|
||||
* @compile/ref=SerialMethodThrows.out -XDrawDiagnostics -Xlint:serial SerialMethodThrows.java
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/*
|
||||
* Container class for various serializable classes with different
|
||||
* kinds of throws clauses. Canonical serialization method signatures:
|
||||
*
|
||||
* private void writeObject(ObjectOutputStream stream)
|
||||
* throws IOException
|
||||
*
|
||||
* ANY-ACCESS-MODIFIER Object writeReplace()
|
||||
* throws ObjectStreamException
|
||||
*
|
||||
* private void readObject(ObjectInputStream stream)
|
||||
* throws IOException, ClassNotFoundException
|
||||
*
|
||||
* private void readObjectNoData()
|
||||
* throws ObjectStreamException
|
||||
*
|
||||
* ANY-ACCESS-MODIFIER Object readResolve()
|
||||
* throws ObjectStreamException
|
||||
*/
|
||||
class SerialMethodThrows {
|
||||
|
||||
// Being declared to throw no exceptions is fine and should not
|
||||
// generate any warnings.
|
||||
static class NoThrows implements Serializable {
|
||||
private static final long serialVersionUID = 42;
|
||||
|
||||
private void writeObject(ObjectOutputStream stream) {
|
||||
try {
|
||||
stream.defaultWriteObject();
|
||||
} catch (IOException e) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream stream) {
|
||||
try {
|
||||
stream.defaultReadObject();
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
private void readObjectNoData() {}
|
||||
|
||||
private Object readResolve() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Being declared to throw the canonical exceptions is fine and
|
||||
// should not generate any warnings.
|
||||
static class ErrorThrows implements Serializable {
|
||||
private static final long serialVersionUID = 42;
|
||||
|
||||
private void writeObject(ObjectOutputStream stream)
|
||||
throws Error {
|
||||
try {
|
||||
stream.defaultWriteObject();
|
||||
} catch (IOException e) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
private Object writeReplace()
|
||||
throws Error {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws Error {
|
||||
try {
|
||||
stream.defaultReadObject();
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
private void readObjectNoData()
|
||||
throws Error {}
|
||||
|
||||
private Object readResolve()
|
||||
throws Error {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Being declared to throw the canonical exceptions is fine and
|
||||
// should not generate any warnings.
|
||||
static class ExactThrows implements Serializable {
|
||||
private static final long serialVersionUID = 42;
|
||||
|
||||
private void writeObject(ObjectOutputStream stream)
|
||||
throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
}
|
||||
|
||||
private Object writeReplace()
|
||||
throws ObjectStreamException {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
}
|
||||
|
||||
private void readObjectNoData()
|
||||
throws ObjectStreamException {}
|
||||
|
||||
private Object readResolve()
|
||||
throws ObjectStreamException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Being declared to throw subclasses of the canonical exceptions
|
||||
// is fine and should not generate any warnings.
|
||||
static class SubclassThrows implements Serializable {
|
||||
private static final long serialVersionUID = 42;
|
||||
|
||||
private void writeObject(ObjectOutputStream stream)
|
||||
throws CustomIOException {
|
||||
try {
|
||||
stream.defaultWriteObject();
|
||||
} catch (IOException e) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
private Object writeReplace()
|
||||
throws CustomObjectStreamException {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws CustomIOException, CustomClassNotFoundException {
|
||||
try {
|
||||
stream.defaultReadObject();
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
private void readObjectNoData()
|
||||
throws CustomObjectStreamException {}
|
||||
|
||||
private Object readResolve()
|
||||
throws CustomObjectStreamException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CustomIOException extends IOException{
|
||||
private static final long serialVersionUID = 1;
|
||||
}
|
||||
|
||||
private static class CustomObjectStreamException extends ObjectStreamException {
|
||||
private static final long serialVersionUID = 2;
|
||||
}
|
||||
|
||||
private static class CustomClassNotFoundException extends ClassNotFoundException {
|
||||
private static final long serialVersionUID = 3;
|
||||
}
|
||||
|
||||
// Use to trigger warnings
|
||||
private static class CustomException extends Exception {
|
||||
private static final long serialVersionUID = 3;
|
||||
}
|
||||
|
||||
// Being declared to throw subclasses of the canonical exceptions
|
||||
// is fine and should not generate any warnings.
|
||||
static class CustomThrows implements Serializable {
|
||||
private static final long serialVersionUID = 42;
|
||||
|
||||
private void writeObject(ObjectOutputStream stream)
|
||||
throws CustomException {
|
||||
try {
|
||||
stream.defaultWriteObject();
|
||||
} catch (IOException e) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
private Object writeReplace()
|
||||
throws CustomException {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws CustomException {
|
||||
try {
|
||||
stream.defaultReadObject();
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
private void readObjectNoData()
|
||||
throws CustomException {}
|
||||
|
||||
private Object readResolve()
|
||||
throws CustomException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
SerialMethodThrows.java:187:22: compiler.warn.serial.method.unexpected.exception: writeObject, SerialMethodThrows.CustomException
|
||||
SerialMethodThrows.java:196:24: compiler.warn.serial.method.unexpected.exception: writeReplace, SerialMethodThrows.CustomException
|
||||
SerialMethodThrows.java:201:22: compiler.warn.serial.method.unexpected.exception: readObject, SerialMethodThrows.CustomException
|
||||
SerialMethodThrows.java:210:22: compiler.warn.serial.method.unexpected.exception: readObjectNoData, SerialMethodThrows.CustomException
|
||||
SerialMethodThrows.java:213:24: compiler.warn.serial.method.unexpected.exception: readResolve, SerialMethodThrows.CustomException
|
||||
5 warnings
|
Loading…
x
Reference in New Issue
Block a user