diff options
15 files changed, 234 insertions, 65 deletions
diff --git a/src/core/lombok/Lombok.java b/src/core/lombok/Lombok.java index db94f05c..a845465f 100644 --- a/src/core/lombok/Lombok.java +++ b/src/core/lombok/Lombok.java @@ -57,4 +57,18 @@ public class Lombok { private static <T extends Throwable> void sneakyThrow0(Throwable t) throws T { throw (T)t; } + + /** + * Returns the parameter directly. <br /> + * + * This method can be used to prevent a static analyzer to determine + * the nullness of the passed parameter. + * + * @param <T> the type of the parameter + * @param value the value to return + * @return value + */ + public static <T> T preventNullAnalysis(T value) { + return value; + } } diff --git a/src/core/lombok/bytecode/FixedClassWriter.java b/src/core/lombok/bytecode/FixedClassWriter.java new file mode 100644 index 00000000..52de2317 --- /dev/null +++ b/src/core/lombok/bytecode/FixedClassWriter.java @@ -0,0 +1,41 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.bytecode; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; + +class FixedClassWriter extends ClassWriter { + FixedClassWriter(ClassReader classReader, int flags) { + super(classReader, flags); + } + + @Override protected String getCommonSuperClass(String type1, String type2) { + //By default, ASM will attempt to live-load the class types, which will fail if meddling with classes in an + //environment with custom classloaders, such as Equinox. It's just an optimization; returning Object is always legal. + try { + return super.getCommonSuperClass(type1, type2); + } catch (Exception e) { + return "java/lang/Object"; + } + } +}
\ No newline at end of file diff --git a/src/core/lombok/bytecode/PostCompilationUtil.java b/src/core/lombok/bytecode/PostCompilationUtil.java new file mode 100644 index 00000000..1c1bb0c1 --- /dev/null +++ b/src/core/lombok/bytecode/PostCompilationUtil.java @@ -0,0 +1,50 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.bytecode; + +import org.objectweb.asm.ClassAdapter; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.commons.JSRInlinerAdapter; + +class PostCompilationUtil { + + private PostCompilationUtil() { + throw new UnsupportedOperationException(); + } + + static byte[] fixJSRInlining(byte[] byteCode) { + ClassReader reader = new ClassReader(byteCode); + ClassWriter writer = new FixedClassWriter(reader, 0); + + ClassVisitor visitor = new ClassAdapter(writer) { + @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + return new JSRInlinerAdapter(super.visitMethod(access, name, desc, signature, exceptions), access, name, desc, signature, exceptions); + } + }; + + reader.accept(visitor, 0); + return writer.toByteArray(); + } +} diff --git a/src/core/lombok/bytecode/PreventNullAnalysisRemover.java b/src/core/lombok/bytecode/PreventNullAnalysisRemover.java new file mode 100644 index 00000000..4dc08bb4 --- /dev/null +++ b/src/core/lombok/bytecode/PreventNullAnalysisRemover.java @@ -0,0 +1,78 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.bytecode; + +import static lombok.bytecode.PostCompilationUtil.fixJSRInlining; + +import java.util.concurrent.atomic.AtomicBoolean; + +import lombok.core.DiagnosticsReceiver; +import lombok.core.PostCompilerTransformation; + +import org.mangosdk.spi.ProviderFor; +import org.objectweb.asm.ClassAdapter; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodAdapter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +@ProviderFor(PostCompilerTransformation.class) +public class PreventNullAnalysisRemover implements PostCompilerTransformation { + + @Override public byte[] applyTransformations(byte[] original, String fileName, DiagnosticsReceiver diagnostics) { + if (!new ClassFileMetaData(original).usesMethod("lombok/Lombok", "preventNullAnalysis")) return null; + + byte[] fixedByteCode = fixJSRInlining(original); + + ClassReader reader = new ClassReader(fixedByteCode); + ClassWriter writer = new FixedClassWriter(reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + + final AtomicBoolean changesMade = new AtomicBoolean(); + + class PreventNullanalysisVisitor extends MethodAdapter { + PreventNullanalysisVisitor(MethodVisitor mv) { + super(mv); + } + + @Override public void visitMethodInsn(int opcode, String owner, String name, String desc) { + boolean hit = true; + if (hit && opcode != Opcodes.INVOKESTATIC) hit = false; + if (hit && !"preventNullAnalysis".equals(name)) hit = false; + if (hit && !"lombok/Lombok".equals(owner)) hit = false; + if (hit && !"(Ljava/lang/Object;)Ljava/lang/Object;".equals(desc)) hit = false; + if (hit) { + changesMade.set(true); + } else { + super.visitMethodInsn(opcode, owner, name, desc); + } + } + } + + reader.accept(new ClassAdapter(writer) { + @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + return new PreventNullanalysisVisitor(super.visitMethod(access, name, desc, signature, exceptions)); + } + }, 0); + return changesMade.get() ? writer.toByteArray() : null; + } +} diff --git a/src/core/lombok/bytecode/SneakyThrowsRemover.java b/src/core/lombok/bytecode/SneakyThrowsRemover.java index 71596f60..a86d26e7 100644 --- a/src/core/lombok/bytecode/SneakyThrowsRemover.java +++ b/src/core/lombok/bytecode/SneakyThrowsRemover.java @@ -1,5 +1,5 @@ /* - * Copyright © 2010 Reinier Zwitserloot and Roel Spilker. + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,8 @@ */ package lombok.bytecode; +import static lombok.bytecode.PostCompilationUtil.*; + import java.util.concurrent.atomic.AtomicBoolean; import lombok.core.DiagnosticsReceiver; @@ -31,45 +33,14 @@ import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.commons.JSRInlinerAdapter; @ProviderFor(PostCompilerTransformation.class) public class SneakyThrowsRemover implements PostCompilerTransformation { - private static class FixedClassWriter extends ClassWriter { - FixedClassWriter(ClassReader classReader, int flags) { - super(classReader, flags); - } - - @Override protected String getCommonSuperClass(String type1, String type2) { - //By default, ASM will attempt to live-load the class types, which will fail if meddling with classes in an - //environment with custom classloaders, such as Equinox. It's just an optimization; returning Object is always legal. - try { - return super.getCommonSuperClass(type1, type2); - } catch (Exception e) { - return "java/lang/Object"; - } - } - } - - protected byte[] fixJSRInlining(byte[] byteCode) { - ClassReader reader = new ClassReader(byteCode); - ClassWriter writer = new FixedClassWriter(reader, 0); - - ClassVisitor visitor = new ClassAdapter(writer) { - @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - return new JSRInlinerAdapter(super.visitMethod(access, name, desc, signature, exceptions), access, name, desc, signature, exceptions); - } - }; - - reader.accept(visitor, 0); - return writer.toByteArray(); - } @Override public byte[] applyTransformations(byte[] original, String fileName, DiagnosticsReceiver diagnostics) { if (!new ClassFileMetaData(original).usesMethod("lombok/Lombok", "sneakyThrow")) return null; diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 019ae637..0db0085f 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009-2010 Reinier Zwitserloot and Roel Spilker. + * Copyright © 2009-2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -610,4 +610,19 @@ public class EclipseHandlerUtil { return problematic; } + + static NameReference createNameReference(String name, Annotation source) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + char[][] nameTokens = fromQualifiedName(name); + long[] pos = new long[nameTokens.length]; + Arrays.fill(pos, p); + + QualifiedNameReference nameReference = new QualifiedNameReference(nameTokens, pos, pS, pE); + nameReference.statementEnd = pE; + + Eclipse.setGeneratedBy(nameReference, source); + return nameReference; + } } diff --git a/src/core/lombok/eclipse/handlers/HandleCleanup.java b/src/core/lombok/eclipse/handlers/HandleCleanup.java index 33ab7fb9..964653bc 100644 --- a/src/core/lombok/eclipse/handlers/HandleCleanup.java +++ b/src/core/lombok/eclipse/handlers/HandleCleanup.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * Copyright © 2009-2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,8 @@ */ package lombok.eclipse.handlers; +import static lombok.eclipse.handlers.EclipseHandlerUtil.createNameReference; + import java.util.Arrays; import lombok.Cleanup; @@ -38,6 +40,7 @@ import org.eclipse.jdt.internal.compiler.ast.Block; import org.eclipse.jdt.internal.compiler.ast.CaseStatement; import org.eclipse.jdt.internal.compiler.ast.CastExpression; import org.eclipse.jdt.internal.compiler.ast.EqualExpression; +import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.IfStatement; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.MemberValuePair; @@ -170,7 +173,19 @@ public class HandleCleanup implements EclipseAnnotationHandler<Cleanup> { Eclipse.setGeneratedBy(varName, ast); NullLiteral nullLiteral = new NullLiteral(pS, pE); Eclipse.setGeneratedBy(nullLiteral, ast); - EqualExpression equalExpression = new EqualExpression(varName, nullLiteral, OperatorIds.NOT_EQUAL); + + MessageSend preventNullAnalysis = new MessageSend(); + Eclipse.setGeneratedBy(preventNullAnalysis, ast); + + preventNullAnalysis.receiver = createNameReference("lombok.Lombok", ast); + preventNullAnalysis.selector = "preventNullAnalysis".toCharArray(); + + preventNullAnalysis.arguments = new Expression[] { varName }; + preventNullAnalysis.nameSourcePosition = p; + preventNullAnalysis.sourceStart = pS; + preventNullAnalysis.sourceEnd = preventNullAnalysis.statementEnd = pE; + + EqualExpression equalExpression = new EqualExpression(preventNullAnalysis, nullLiteral, OperatorIds.NOT_EQUAL); equalExpression.sourceStart = pS; equalExpression.sourceEnd = pE; Eclipse.setGeneratedBy(equalExpression, ast); diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java index ed13fd1b..23d24fb0 100644 --- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009-2010 Reinier Zwitserloot and Roel Spilker. + * Copyright © 2009-2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java index 736e6e43..1df33e89 100644 --- a/src/core/lombok/eclipse/handlers/HandleLog.java +++ b/src/core/lombok/eclipse/handlers/HandleLog.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -38,8 +38,6 @@ import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.MessageSend; -import org.eclipse.jdt.internal.compiler.ast.NameReference; -import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; @@ -159,21 +157,6 @@ public class HandleLog { return typeReference; } - private static NameReference createNameReference(String name, Annotation source) { - int pS = source.sourceStart, pE = source.sourceEnd; - long p = (long)pS << 32 | pE; - - char[][] nameTokens = fromQualifiedName(name); - long[] pos = new long[nameTokens.length]; - Arrays.fill(pos, p); - - QualifiedNameReference nameReference = new QualifiedNameReference(nameTokens, pos, pS, pE); - nameReference.statementEnd = pE; - - Eclipse.setGeneratedBy(nameReference, source); - return nameReference; - } - /** * Handles the {@link lombok.extern.apachecommons.Log} annotation for Eclipse. */ diff --git a/src/core/lombok/javac/handlers/HandleCleanup.java b/src/core/lombok/javac/handlers/HandleCleanup.java index 779dd3ea..d72898b8 100644 --- a/src/core/lombok/javac/handlers/HandleCleanup.java +++ b/src/core/lombok/javac/handlers/HandleCleanup.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * Copyright © 2009-2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -45,6 +45,7 @@ import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.JCTree.JCIf; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTypeCast; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; @@ -115,7 +116,8 @@ public class HandleCleanup implements JavacAnnotationHandler<Cleanup> { List<JCStatement> cleanupCall = List.<JCStatement>of(maker.Exec( maker.Apply(List.<JCExpression>nil(), cleanupMethod, List.<JCExpression>nil()))); - JCBinary isNull = maker.Binary(JCTree.NE, maker.Ident(decl.name), maker.Literal(TypeTags.BOT, null)); + JCMethodInvocation preventNullAnalysis = maker.Apply(List.<JCExpression>nil(), JavacHandlerUtil.chainDotsString(maker, annotationNode, "lombok.Lombok.preventNullAnalysis"), List.<JCExpression>of(maker.Ident(decl.name))); + JCBinary isNull = maker.Binary(JCTree.NE, preventNullAnalysis, maker.Literal(TypeTags.BOT, null)); JCIf ifNotNullCleanup = maker.If(isNull, maker.Block(0, cleanupCall), null); diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index c5475fb1..96113bc4 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -1,5 +1,5 @@ /* - * Copyright © 2009-2010 Reinier Zwitserloot and Roel Spilker. + * Copyright © 2009-2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/test/transform/resource/after-delombok/CleanupName.java b/test/transform/resource/after-delombok/CleanupName.java index 0201008e..37a8d117 100644 --- a/test/transform/resource/after-delombok/CleanupName.java +++ b/test/transform/resource/after-delombok/CleanupName.java @@ -4,7 +4,7 @@ class CleanupName { try { System.out.println(o); } finally { - if (o != null) { + if (lombok.Lombok.preventNullAnalysis(o) != null) { o.toString(); } } @@ -14,7 +14,7 @@ class CleanupName { try { System.out.println(o); } finally { - if (o != null) { + if (lombok.Lombok.preventNullAnalysis(o) != null) { o.toString(); } } diff --git a/test/transform/resource/after-delombok/CleanupPlain.java b/test/transform/resource/after-delombok/CleanupPlain.java index 1a19442f..67c82f60 100644 --- a/test/transform/resource/after-delombok/CleanupPlain.java +++ b/test/transform/resource/after-delombok/CleanupPlain.java @@ -9,12 +9,12 @@ class CleanupPlain { out.flush(); } } finally { - if (out != null) { + if (lombok.Lombok.preventNullAnalysis(out) != null) { out.close(); } } } finally { - if (in != null) { + if (lombok.Lombok.preventNullAnalysis(in) != null) { in.close(); } } diff --git a/test/transform/resource/after-ecj/CleanupName.java b/test/transform/resource/after-ecj/CleanupName.java index 4011721b..8948e91d 100644 --- a/test/transform/resource/after-ecj/CleanupName.java +++ b/test/transform/resource/after-ecj/CleanupName.java @@ -10,7 +10,7 @@ class CleanupName { } finally { - if ((o != null)) + if ((lombok.Lombok.preventNullAnalysis(o) != null)) { o.toString(); } @@ -24,7 +24,7 @@ class CleanupName { } finally { - if ((o != null)) + if ((lombok.Lombok.preventNullAnalysis(o) != null)) { o.toString(); } diff --git a/test/transform/resource/after-ecj/CleanupPlain.java b/test/transform/resource/after-ecj/CleanupPlain.java index fe8d7571..6eaa4377 100644 --- a/test/transform/resource/after-ecj/CleanupPlain.java +++ b/test/transform/resource/after-ecj/CleanupPlain.java @@ -18,7 +18,7 @@ class CleanupPlain { } finally { - if ((out != null)) + if ((lombok.Lombok.preventNullAnalysis(out) != null)) { out.close(); } @@ -26,7 +26,7 @@ class CleanupPlain { } finally { - if ((in != null)) + if ((lombok.Lombok.preventNullAnalysis(in) != null)) { in.close(); } |