diff --git a/api.debugger.jpda/apichanges.xml b/api.debugger.jpda/apichanges.xml --- a/api.debugger.jpda/apichanges.xml +++ b/api.debugger.jpda/apichanges.xml @@ -835,6 +835,28 @@ + + + A possibility to get/set mirror objects from debugger variables. + + + + + + MutableVariable interface is introduced. It's to be implemented by + variables that can change their values. Field, + LocalVariable and JPDAWatch now extend + MutableVariable. +

+ Object createMirrorObject() method is added to Variable + class and void setFromMirrorObject(Object obj) method + is declared by MutableVariable. + + + + + + diff --git a/api.debugger.jpda/manifest.mf b/api.debugger.jpda/manifest.mf --- a/api.debugger.jpda/manifest.mf +++ b/api.debugger.jpda/manifest.mf @@ -1,6 +1,6 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.api.debugger.jpda/2 OpenIDE-Module-Localizing-Bundle: org/netbeans/api/debugger/jpda/Bundle.properties -OpenIDE-Module-Specification-Version: 2.43 +OpenIDE-Module-Specification-Version: 2.44 OpenIDE-Module-Package-Dependencies: com.sun.jdi[VirtualMachineManager] diff --git a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/Field.java b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/Field.java --- a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/Field.java +++ b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/Field.java @@ -58,7 +58,7 @@ * @see ObjectVariable * @author Jan Jancura */ -public interface Field extends Variable { +public interface Field extends MutableVariable { /** * Declared name of field. @@ -100,6 +100,7 @@ * @return sets value of this field represented as text * @throws InvalidExpressionException if the expression is not correct */ + @Override public abstract void setValue (String value) throws InvalidExpressionException; } diff --git a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDAWatch.java b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDAWatch.java --- a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDAWatch.java +++ b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDAWatch.java @@ -57,7 +57,7 @@ * @author Jan Jancura */ -public interface JPDAWatch extends Variable { +public interface JPDAWatch extends MutableVariable { /** * Watched expression. @@ -105,6 +105,7 @@ * * @param value a new value of this variable represented as text */ + @Override public abstract void setValue (String value) throws InvalidExpressionException; /** diff --git a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/LocalVariable.java b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/LocalVariable.java --- a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/LocalVariable.java +++ b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/LocalVariable.java @@ -58,7 +58,7 @@ * @see ObjectVariable * @author Jan Jancura */ -public interface LocalVariable extends Variable { +public interface LocalVariable extends MutableVariable { /** * Declared name of local. @@ -87,6 +87,7 @@ * @param value a new value of this local represented as text * @throws InvalidExpressionException if the expression is not correct */ + @Override public abstract void setValue (String value) throws InvalidExpressionException; } diff --git a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/MutableVariable.java b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/MutableVariable.java new file mode 100644 --- /dev/null +++ b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/MutableVariable.java @@ -0,0 +1,81 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * 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 + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. 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 + * nbbuild/licenses/CDDL-GPL-2-CP. 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. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * 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 do not 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. + * + * Contributor(s): + * + * Portions Copyrighted 2013 Sun Microsystems, Inc. + */ +package org.netbeans.api.debugger.jpda; + +import java.io.InvalidObjectException; + +/** + * Represents a variable that can be modified. + * + *

+ * Since JDI interfaces evolve from one version to another, it's strongly recommended
+ * not to implement this interface in client code. New methods can be added to
+ * this interface at any time to keep up with the JDI functionality.
+ * + * @see LocalVariable + * @see Field + * @see JPDAWatch + * + * @author Martin Entlicher + * @since 2.44 + */ +public interface MutableVariable extends Variable { + + /** + * Sets a value represented as text, to this variable. + * + * @param value The string value to be set to this variable + * @throws InvalidExpressionException if the expression is not correct + */ + void setValue (String value) throws InvalidExpressionException; + + /** + * Set the value of this variable to match the given mirror object. + * + * @param obj The mirror object + * @throws InvalidObjectException when it was not possible to set value of + * this variable from the provided object. + * @see Variable#createMirrorObject() + */ + void setFromMirrorObject(Object obj) throws InvalidObjectException; + +} diff --git a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/Variable.java b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/Variable.java --- a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/Variable.java +++ b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/Variable.java @@ -77,4 +77,14 @@ * @return text representation of current value of "this" variable */ public abstract String getValue (); + + /** + * Create an object in this JVM, which mirrors the value of this variable in + * the target JVM. + * + * @return The mirror object, or null when a mirror object can not be created. + * @since 2.44 + */ + Object createMirrorObject(); + } diff --git a/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/MirrorValuesTest.java b/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/MirrorValuesTest.java new file mode 100644 --- /dev/null +++ b/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/MirrorValuesTest.java @@ -0,0 +1,183 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * 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 + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. 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 + * nbbuild/licenses/CDDL-GPL-2-CP. 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. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * 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 do not 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. + * + * Contributor(s): + * + * Portions Copyrighted 2013 Sun Microsystems, Inc. + */ +package org.netbeans.api.debugger.jpda; + +import java.awt.Color; +import java.awt.Point; +import java.io.File; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import junit.framework.Test; +import org.netbeans.api.debugger.DebuggerManager; +import org.netbeans.junit.NbTestCase; + +/** + * Tests {@link Variable#createMirrorObject()} and {@link MutableVariable#setFromMirrorObject(java.lang.Object)}. + * + * @author Martin Entlicher + */ +public class MirrorValuesTest extends NbTestCase { + + private static final String CLASS_NAME = + "org.netbeans.api.debugger.jpda.testapps.MirrorValuesApp"; + + private JPDASupport support; + private DebuggerManager dm = DebuggerManager.getDebuggerManager (); + + public MirrorValuesTest(String s) { + super(s); + } + + public static Test suite() { + return JPDASupport.createTestSuite(MirrorValuesTest.class); + } + + public void testMirrors() throws Exception { + try { + Utils.BreakPositions bp = Utils.getBreakPositions(System.getProperty ("test.dir.src") + + "org/netbeans/api/debugger/jpda/testapps/MirrorValuesApp.java"); + LineBreakpoint lb = bp.getLineBreakpoints().get(0); + dm.addBreakpoint (lb); + + support = JPDASupport.attach (CLASS_NAME); + + support.waitState (JPDADebugger.STATE_STOPPED); // breakpoint hit + + CallStackFrame sf = support.getDebugger ().getCurrentCallStackFrame (); + LocalVariable [] vars = sf.getLocalVariables (); + Map variablesByName = getVariablesByName(vars); + Map mirrorsByName = getMirrorsByName(); + + Variable v; + Object m; + + // Test of createMirrorObject(): + for (String name : mirrorsByName.keySet()) { + v = variablesByName.get(name); + m = v.createMirrorObject(); + assertNotNull(name, m); + Object mm = mirrorsByName.get(name); + if (mm.getClass().isArray()) { + assertTrue(name+" is array", m.getClass().isArray()); + assertTrue(name+" array "+arrayToString(mm)+ + " does not equal to "+arrayToString(m), + compareArrays(mm, m)); + } else { + assertEquals(name, mm, m); + } + } + + // Test of setFromMirrorObject(): + v = variablesByName.get("boo"); + assertEquals("boo", "true", v.getValue()); + ((MutableVariable) v).setFromMirrorObject(Boolean.FALSE); + assertEquals("boo", "false", v.getValue()); + + v = variablesByName.get("i"); + assertEquals("i", "10000", v.getValue()); + ((MutableVariable) v).setFromMirrorObject(12345); + assertEquals("i", "12345", v.getValue()); + + v = variablesByName.get("color"); + assertEquals("color", "java.awt.Color[r=255,g=0,b=0]", ((ObjectVariable) v).getToStringValue()); + ((MutableVariable) v).setFromMirrorObject(Color.GREEN); + assertEquals("color", "java.awt.Color[r=0,g=255,b=0]", ((ObjectVariable) v).getToStringValue()); + + } finally { + support.doFinish (); + } + + } + + private static boolean compareArrays(Object arr1, Object arr2) { + if (arr1 instanceof Object[]) { + return Arrays.deepEquals((Object[]) arr1, (Object[]) arr2); + } else if (arr1 instanceof int[]) { + return Arrays.equals((int[]) arr1, (int[]) arr2); + } else { + throw new IllegalStateException(arr1+", "+arr2); + } + } + + private static String arrayToString(Object a) { + if (a instanceof Object[]) { + return Arrays.deepToString((Object[]) a); + } else if (a instanceof int[]) { + return Arrays.toString((int[]) a); + } else { + throw new IllegalStateException(a.toString()); + } + } + + private static Map getVariablesByName(LocalVariable[] vars) { + Map map = new HashMap(); + for (LocalVariable lv : vars) { + assertTrue("Not mutable", lv instanceof MutableVariable); + map.put(lv.getName(), lv); + } + return map; + } + + private static Map getMirrorsByName() { + String[] names = { "boo", "b", "s", "i", "l", + "f", "d", + "iarr", + "darr", + "str", "date", "color", + "point", "file" }; + Object[] mirrors = { true, (byte) 5, (short) 512, 10000, Long.MAX_VALUE, + 12.12f, 1e150, + new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + new double[][] { { 0.1, 0.2, 0.3 }, { 1.1, 1.2, 1.3 }, { 2.1, 2.2, 2.3 } }, + "A String", new Date(1000000000l), Color.RED, + new Point(10, 10), new File("/tmp/Foo.txt") }; + + Map map = new HashMap(); + assertEquals(names.length, mirrors.length); + for (int i = 0; i < names.length; i++) { + map.put(names[i], mirrors[i]); + } + return map; + } +} diff --git a/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/testapps/MirrorValuesApp.java b/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/testapps/MirrorValuesApp.java new file mode 100644 --- /dev/null +++ b/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/testapps/MirrorValuesApp.java @@ -0,0 +1,84 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * 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 + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. 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 + * nbbuild/licenses/CDDL-GPL-2-CP. 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. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * 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 do not 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. + * + * Contributor(s): + * + * Portions Copyrighted 2013 Sun Microsystems, Inc. + */ +package org.netbeans.api.debugger.jpda.testapps; + +import java.awt.Color; +import java.awt.Point; +import java.io.File; +import java.util.Date; + +/** + * A test application for mirror values. + * + * @author Martin Entlicher + */ +public class MirrorValuesApp { + + public static void main(String[] args) { + MirrorValuesApp mva = new MirrorValuesApp(); + mva.mirrors(); + } + + private void mirrors() { + boolean boo = true; + byte b = 5; + short s = 512; + int i = 10000; + long l = Long.MAX_VALUE; + float f = 12.12f; + double d = 1e150; + + int[] iarr = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + double[][] darr = new double[][] { { 0.1, 0.2, 0.3 }, { 1.1, 1.2, 1.3 }, { 2.1, 2.2, 2.3 } }; + + String str = "A String"; + + Date date = new Date(1000000000l); + Color color = Color.RED; + Point point = new Point(10, 10); + File file = new File("/tmp/Foo.txt"); + + Color[][] colors = new Color[][] { { Color.WHITE, Color.BLACK }, { Color.YELLOW, Color.GRAY } }; + + System.currentTimeMillis(); // LBREAKPOINT + } +}