From 2193e9e5df60be3a8078d25071ce8f58a1137fc4 Mon Sep 17 00:00:00 2001 From: Philip Helger Date: Wed, 27 Mar 2019 19:43:44 +0100 Subject: [PATCH] Added support for `try-with-resources` support (issue #67 from @gmcfall) --- README.md | 3 + .../com/helger/jcodemodel/JCatchBlock.java | 2 +- .../java/com/helger/jcodemodel/JTryBlock.java | 87 +++++++++++++- .../com/helger/jcodemodel/JTryResource.java | 41 +++++++ .../helger/jcodemodel/JTryResourcesTest.java | 110 ++++++++++++++++++ 5 files changed, 238 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/helger/jcodemodel/JTryResource.java create mode 100644 src/test/java/com/helger/jcodemodel/JTryResourcesTest.java diff --git a/README.md b/README.md index c72560dd..fd0b8587 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,9 @@ A site with the links to the [API docs](http://phax.github.io/jcodemodel/) etc. # News and noteworthy +* v3.2.3 - work in progress + * Extended `JTryBlock` API to have more control. + * Added support for `try-with-resources` support (issue #67 from @gmcfall) * v3.2.2 - 2019-02-25 * Using `jsr305` instead of `annotations` in POM (issue #66 from @jjYBdx4IL) * v3.2.1 - 2019-01-23 diff --git a/src/main/java/com/helger/jcodemodel/JCatchBlock.java b/src/main/java/com/helger/jcodemodel/JCatchBlock.java index b1ddae8f..6f574a18 100644 --- a/src/main/java/com/helger/jcodemodel/JCatchBlock.java +++ b/src/main/java/com/helger/jcodemodel/JCatchBlock.java @@ -52,7 +52,7 @@ public class JCatchBlock implements IJGenerable private JVar m_aVar; private final JBlock m_aBody = new JBlock (); - protected JCatchBlock (@Nonnull final AbstractJClass aException) + public JCatchBlock (@Nonnull final AbstractJClass aException) { m_aException = aException; } diff --git a/src/main/java/com/helger/jcodemodel/JTryBlock.java b/src/main/java/com/helger/jcodemodel/JTryBlock.java index 06c68f36..4d252ea9 100644 --- a/src/main/java/com/helger/jcodemodel/JTryBlock.java +++ b/src/main/java/com/helger/jcodemodel/JTryBlock.java @@ -41,16 +41,16 @@ package com.helger.jcodemodel; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import javax.annotation.Nonnull; /** - * Try statement with Catch and/or Finally clause + * Try statement with Catch and/or Finally clause. */ public class JTryBlock implements IJStatement { + private final List m_aResources = new ArrayList <> (); private final JBlock m_aBody = new JBlock (); private final List m_aCatches = new ArrayList <> (); private JBlock m_aFinally; @@ -58,12 +58,35 @@ public class JTryBlock implements IJStatement public JTryBlock () {} + /** + * @return A mutable list of all try-resources for "try-with-resources". + * @since 3.2.3 + */ + @Nonnull + public List tryResources () + { + return m_aResources; + } + + /** + * @return The non-null try-body. + */ @Nonnull public JBlock body () { return m_aBody; } + /** + * Add a new catch block for the specification exception class. The variable + * name is automatically created. + * + * @param aException + * The exception class to catch. May not be null. + * @return the created catch block for further customization and never + * null. + * @see #catches() + */ @Nonnull public JCatchBlock _catch (@Nonnull final AbstractJClass aException) { @@ -72,12 +95,32 @@ public JCatchBlock _catch (@Nonnull final AbstractJClass aException) return cb; } + /** + * Get a list of all catch blocks. Since v3.2.3 the returned list is mutable. + * Previously it was immutable. + * + * @return A mutable list of all contained catch blocks. + */ @Nonnull public List catches () { - return Collections.unmodifiableList (m_aCatches); + return m_aCatches; + } + + /** + * @return true if at least one catch block is present, + * false if not. + * @since 3.2.3 + */ + public boolean hasCatchBlock () + { + return !m_aCatches.isEmpty (); } + /** + * @return A non-null finally block. The block is automatically + * created the first time you call this method. + */ @Nonnull public JBlock _finally () { @@ -86,9 +129,45 @@ public JBlock _finally () return m_aFinally; } + /** + * Remove the finally block - this allows to reset an eventually accidentally + * created finally block. + * + * @since 3.2.3 + */ + public void resetFinally () + { + m_aFinally = null; + } + + /** + * @return true if a finally block is present, false + * if not. + * @since 3.2.3 + */ + public boolean hasFinally () + { + return m_aFinally != null; + } + public void state (@Nonnull final IJFormatter f) { - f.print ("try").generable (m_aBody); + f.print ("try"); + if (!m_aResources.isEmpty ()) + { + f.print ('('); + boolean bFirst = true; + for (final JTryResource aResource : m_aResources) + { + if (bFirst) + bFirst = false; + else + f.print (';').newline (); + f.generable (aResource); + } + f.print (')'); + } + f.generable (m_aBody); for (final JCatchBlock cb : m_aCatches) f.generable (cb); if (m_aFinally != null) diff --git a/src/main/java/com/helger/jcodemodel/JTryResource.java b/src/main/java/com/helger/jcodemodel/JTryResource.java new file mode 100644 index 00000000..4cc9dcb8 --- /dev/null +++ b/src/main/java/com/helger/jcodemodel/JTryResource.java @@ -0,0 +1,41 @@ +package com.helger.jcodemodel; + +import javax.annotation.Nonnull; + +/** + * This class represents a single resources that is used in try-with-resources + * statement. See {@link JTryBlock}. + * + * @author Philip Helger + * @since 3.2.3 + */ +public class JTryResource implements IJGenerable +{ + private final JVar m_aVar; + + public JTryResource (@Nonnull final AbstractJType aType, + @Nonnull final String sName, + @Nonnull final IJExpression aInitExpr) + { + this (JMod.FINAL, aType, sName, aInitExpr); + } + + public JTryResource (final int nMods, + @Nonnull final AbstractJType aType, + @Nonnull final String sName, + @Nonnull final IJExpression aInitExpr) + { + m_aVar = new JVar (JMods.forVar (nMods), aType, sName, aInitExpr); + } + + @Nonnull + public JVar var () + { + return m_aVar; + } + + public void generate (@Nonnull final IJFormatter aFormatter) + { + aFormatter.var (m_aVar); + } +} diff --git a/src/test/java/com/helger/jcodemodel/JTryResourcesTest.java b/src/test/java/com/helger/jcodemodel/JTryResourcesTest.java new file mode 100644 index 00000000..2cf9eab7 --- /dev/null +++ b/src/test/java/com/helger/jcodemodel/JTryResourcesTest.java @@ -0,0 +1,110 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved. + * Portions Copyright 2013-2019 Philip Helger + contributors + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html + * or packager/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at packager/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * Oracle designates this particular file as subject to the "Classpath" + * exception as provided by Oracle in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package com.helger.jcodemodel; + +import static org.junit.Assert.assertEquals; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; + +import org.junit.Test; + +import com.helger.jcodemodel.util.CodeModelTestsHelper; +import com.helger.jcodemodel.writer.JCMWriter; + +/** + * Test class for class {@link JTryResource}. + * + * @author Philip Helger + */ +public final class JTryResourcesTest +{ + private static final String CRLF = JCMWriter.getDefaultNewLine (); + + @Test + public void testWith1 () + { + final JCodeModel cm = new JCodeModel (); + + final JTryBlock aTB = new JTryBlock (); + + final JTryResource aTR1 = new JTryResource (cm.ref (OutputStream.class), + "os", + cm.ref (ByteArrayOutputStream.class)._new ()); + aTB.tryResources ().add (aTR1); + aTB.body ().add (aTR1.var ().invoke ("read")); + assertEquals ("try(final java.io.OutputStream os = new java.io.ByteArrayOutputStream()) {" + + CRLF + + " os.read();" + + CRLF + + "}" + + CRLF, + CodeModelTestsHelper.toString (aTB)); + } + + @Test + public void testWith2 () + { + final JCodeModel cm = new JCodeModel (); + + final JTryBlock aTB = new JTryBlock (); + + final JTryResource aTR1 = new JTryResource (cm.ref (OutputStream.class), + "os", + cm.ref (ByteArrayOutputStream.class)._new ()); + aTB.tryResources ().add (aTR1); + final JTryResource aTR2 = new JTryResource (cm.ref (BufferedOutputStream.class), + "bos", + cm.ref (BufferedOutputStream.class)._new ().arg (aTR1.var ())); + aTB.tryResources ().add (aTR2); + aTB.body ().add (aTR2.var ().invoke ("readLine")); + assertEquals ("try(final java.io.OutputStream os = new java.io.ByteArrayOutputStream();" + + CRLF + + "final java.io.BufferedOutputStream bos = new java.io.BufferedOutputStream(os)) {" + + CRLF + + " bos.readLine();" + + CRLF + + "}" + + CRLF, + CodeModelTestsHelper.toString (aTB)); + } +}