6692027: Custom subclasses of QueryEval don't serialize

Remove non-public superclass of QueryEval

Reviewed-by: dfuchs
This commit is contained in:
Eamonn McManus 2008-04-22 18:58:40 +02:00
parent 3c827ac2b0
commit 1ca7f71818
9 changed files with 145 additions and 18 deletions

@ -100,12 +100,13 @@ class AndQueryExp extends QueryEval implements QueryExp {
/**
* Returns a string representation of this AndQueryExp
*/
public String toString() {
return "(" + exp1 + ") and (" + exp2 + ")";
}
@Override
public String toString() {
return "(" + exp1 + ") and (" + exp2 + ")";
}
@Override
String toQueryString() {
@Override
String toQueryString() {
// Parentheses are only added if needed to disambiguate.
return parens(exp1) + " and " + parens(exp2);
}

@ -135,6 +135,7 @@ class BetweenQueryExp extends QueryEval implements QueryExp {
/**
* Returns the string representing the object.
*/
@Override
public String toString() {
return "(" + exp1 + ") between (" + exp2 + ") and (" + exp3 + ")";
}

@ -187,11 +187,11 @@ class BinaryRelQueryExp extends QueryEval implements QueryExp {
/**
* Returns the string representing the object.
*/
@Override
public String toString() {
return "(" + exp1 + ") " + relOpString() + " (" + exp2 + ")";
}
@Override
String toQueryString() {
return exp1 + " " + relOpString() + " " + exp2;
}

@ -91,7 +91,6 @@ class NotQueryExp extends QueryEval implements QueryExp {
return "not (" + exp + ")";
}
@Override
String toQueryString() {
return "not (" + Query.toString(exp) + ")";
}

@ -223,8 +223,7 @@ import javax.management.QueryExp;
* @since 1.5
*/
@SuppressWarnings("serial") // don't complain serialVersionUID not constant
public class ObjectName extends ToQueryString
implements Comparable<ObjectName>, QueryExp {
public class ObjectName implements Comparable<ObjectName>, QueryExp {
/**
* A structure recording property structure and
@ -1781,7 +1780,6 @@ public class ObjectName extends ToQueryString
return getSerializedNameString();
}
@Override
String toQueryString() {
return "LIKE " + Query.value(toString());
}

@ -100,6 +100,7 @@ class OrQueryExp extends QueryEval implements QueryExp {
/**
* Returns a string representation of this OrQueryExp
*/
@Override
public String toString() {
return "(" + exp1 + ") or (" + exp2 + ")";
}

@ -979,8 +979,18 @@ package javax.management;
if (query == null)
return null;
if (query instanceof ToQueryString)
return ((ToQueryString) query).toQueryString();
// This is ugly. At one stage we had a non-public class called
// ToQueryString with the toQueryString() method, and every class
// mentioned here inherited from that class. But that interfered
// with serialization of custom subclasses of e.g. QueryEval. Even
// though we could make it work by adding a public constructor to this
// non-public class, that seemed fragile because according to the
// serialization spec it shouldn't work. If only non-public interfaces
// could have non-public methods.
if (query instanceof ObjectName)
return ((ObjectName) query).toQueryString();
if (query instanceof QueryEval)
return ((QueryEval) query).toQueryString();
return query.toString();
}

@ -25,20 +25,15 @@
package javax.management;
// java import
import java.io.Serializable;
// RI import
import javax.management.MBeanServer;
/**
* Allows a query to be performed in the context of a specific MBean server.
*
* @since 1.5
*/
public abstract class QueryEval extends ToQueryString implements Serializable {
public abstract class QueryEval implements Serializable {
/* Serial version */
private static final long serialVersionUID = 2675899265640874796L;
@ -80,4 +75,10 @@ public abstract class QueryEval extends ToQueryString implements Serializable {
public static MBeanServer getMBeanServer() {
return server.get();
}
// Subclasses in this package can override this method to return a different
// string.
String toQueryString() {
return toString();
}
}

@ -0,0 +1,116 @@
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test
* @bug 6692027
* @summary Check that custom subclasses of QueryEval can be serialized.
* @author Eamonn McManus
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.management.ManagementFactory;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.QueryEval;
import javax.management.QueryExp;
public class CustomQueryTest {
public static interface CountMBean {
public int getCount();
public void increment();
}
public static class Count implements CountMBean {
private AtomicInteger count = new AtomicInteger();
public int getCount() {
return count.get();
}
public void increment() {
count.incrementAndGet();
}
}
public static final ObjectName countName;
static {
try {
countName = new ObjectName("d:type=Count");
} catch (MalformedObjectNameException e) {
throw new AssertionError(e);
}
}
/* A query that calls the increment method of the Count MBean every time
* it is evaluated. If there is no ObjectName filter, the query will be
* evaluated for every MBean in the MBean Server, so the count will be
* incremented by the number of MBeans.
*/
public static class IncrQuery extends QueryEval implements QueryExp {
public boolean apply(ObjectName name) {
try {
getMBeanServer().invoke(countName, "increment", null, null);
return true;
} catch (Throwable t) {
t.printStackTrace();
System.exit(1);
throw new AssertionError(); // not reached
}
}
}
public static void main(String[] args) throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
mbs.registerMBean(new Count(), countName);
int mbeanCount = mbs.getMBeanCount();
QueryExp query = new IncrQuery();
Set<ObjectName> names = mbs.queryNames(null, query);
assertEquals(mbeanCount, names.size());
assertEquals(mbeanCount, mbs.getAttribute(countName, "Count"));
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream oout = new ObjectOutputStream(bout);
oout.writeObject(query);
oout.close();
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream oin = new ObjectInputStream(bin);
query = (QueryExp) oin.readObject();
names = mbs.queryNames(null, query);
assertEquals(mbeanCount * 2, mbs.getAttribute(countName, "Count"));
}
private static void assertEquals(Object expected, Object actual)
throws Exception {
if (!expected.equals(actual)) {
String failure = "FAILED: expected " + expected + ", got " + actual;
throw new Exception(failure);
}
}
}