Preparing for custom rulesets

git-svn-id: https://pmd.svn.sourceforge.net/svnroot/pmd/trunk@1457 51baf565-9d33-0410-a72c-fc3788e3496d
This commit is contained in:
Ole-Martin Mork
2003-02-21 01:03:47 +00:00
parent 657b827666
commit d09bbf640c
8 changed files with 553 additions and 29 deletions

View File

@ -29,3 +29,11 @@ LBL_settings=PMD Settings
PROP_rules=Rules
HINT_rules=The rules that the pmd action uses
Services/pmd-config-option.settings=\PMD Settings
HINT_classpath=The classpath for custom rules
PROP_classpath=Classpath
PROP_rulesets=Rulesets
HINT_rulesets=The custom rulesets to use

View File

@ -41,24 +41,22 @@ public class PMDOptionsSettings extends SystemOption {
/** The serialVersionUID. Don't change! */
private final static long serialVersionUID = 8418202279282091070L;
/**
* The constant for the rulesets property
* @deprecated this property is not in use.
*/
public final static String PROP_RULESETS = "rulesets";
/** The constant for the rulesets property */
public final static String PROP_RULES = "rules";
public final static String PROP_CLASSPATH = "classpath";
public final static String PROP_RULESETS = "rulesets";
/** The default rules.*/
private static final String DEFAULT_RULES =
private static final String DEFAULT_RULES =
"AvoidDuplicateLiterals, StringToString, StringInstantiation, JUnitStaticSuite, " +
"JUnitSpelling, ForLoopsMustUseBracesRule, IfElseStmtsMustUseBracesRule, " +
"WhileLoopsMustUseBracesRule, IfStmtsMustUseBraces, EmptyCatchBlock, EmptyIfStmt, " +
"EmptyWhileStmt, JumbledIncrementer, UnnecessaryConversionTemporaryRule, " +
"EmptyWhileStmt, JumbledIncrementer, UnnecessaryConversionTemporaryRule, " +
"OverrideBothEqualsAndHashcodeRule, EmptyTryBlock, EmptySwitchStatements, " +
"EmptyFinallyBlock, UnusedLocalVariable, UnusedPrivateField, UnusedFormalParameter, " +
"UnnecessaryConstructorRule, UnusedPrivateMethod, SwitchStmtsShouldHaveDefault, " +
"UnnecessaryConstructorRule, UnusedPrivateMethod, SwitchStmtsShouldHaveDefault, " +
"SimplifyBooleanReturnsRule, LooseCouplingRule, AvoidDeeplyNestedIfStmts, " +
"AvoidReassigningParametersRule, OnlyOneReturn, UseSingletonRule, " +
"DontImportJavaLang, UnusedImports, DuplicateImports, ";
@ -68,7 +66,6 @@ public class PMDOptionsSettings extends SystemOption {
/** Sets the default rulesets and initializes the option */
protected void initialize() {
super.initialize();
setRulesets( "" );
setRules( DEFAULT_RULES );
}
@ -104,24 +101,6 @@ public class PMDOptionsSettings extends SystemOption {
}
/** Returns the rulesets property
* @deprecated not used anymore, use {@link #getRules}
* @return the rulesets property
*/
public String getRulesets() {
return ( String )getProperty( PROP_RULESETS );
}
/** Sets the rulesets property
* @deprecated not used anymore, use {@link #setRules}
* @param rulesets the rulesets value to set
*/
public void setRulesets( String rulesets ) {
putProperty( PROP_RULESETS, rulesets, true );
}
/**
* Returns the rulesets property
*
@ -141,4 +120,36 @@ public class PMDOptionsSettings extends SystemOption {
putProperty( PROP_RULES, rules, true );
}
/** Getter for property classpath.
* @return Value of property classpath.
*
*/
public String getClasspath() {
return (String)getProperty( PROP_CLASSPATH );
}
/** Setter for property classpath.
* @param classpath New value of property classpath.
*
*/
public void setClasspath(String classpath) {
putProperty( PROP_CLASSPATH, classpath, true );
}
/** Getter for property rulesets.
* @return Value of property rulesets.
*
*/
public String getRulesets() {
return (String)getProperty( PROP_RULESETS );
}
/** Setter for property rulesets.
* @param rulesets New value of property rulesets.
*
*/
public void setRulesets(String rulesets) {
putProperty( PROP_RULESETS, rulesets, true );
}
}

View File

@ -36,6 +36,7 @@ import org.openide.ErrorManager;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import pmd.config.ui.RuleEditor;
import pmd.config.ui.RuleSetChooserEditor;
/**
* Description of {@link PMDOptionsSettings}.
@ -51,13 +52,24 @@ public class PMDOptionsSettingsBeanInfo extends SimpleBeanInfo {
* @return the description of the rulesets property
*/
public PropertyDescriptor[] getPropertyDescriptors() {
PropertyDescriptor descriptor[] = new PropertyDescriptor[1];
PropertyDescriptor descriptor[] = new PropertyDescriptor[3];
try {
PropertyDescriptor rules = new PropertyDescriptor( "rules", PMDOptionsSettings.class, "getRules", "setRules" );
rules.setDisplayName( NbBundle.getMessage( PMDOptionsSettingsBeanInfo.class, "PROP_rules" ) );
rules.setShortDescription( NbBundle.getMessage( PMDOptionsSettingsBeanInfo.class, "HINT_rules" ) );
rules.setPropertyEditorClass( RuleEditor.class );
descriptor[0] = rules;
PropertyDescriptor classpath = new PropertyDescriptor( "classpath", PMDOptionsSettings.class, "getClasspath", "setClasspath" );
classpath.setDisplayName( NbBundle.getMessage( PMDOptionsSettingsBeanInfo.class, "PROP_classpath" ) );
classpath.setShortDescription( NbBundle.getMessage( PMDOptionsSettingsBeanInfo.class, "HINT_classpath" ) );
descriptor[1] = classpath;
PropertyDescriptor rulesets = new PropertyDescriptor( "rulesets", PMDOptionsSettings.class, "getRulesets", "setRulesets" );
rulesets.setDisplayName( NbBundle.getMessage( PMDOptionsSettingsBeanInfo.class, "PROP_rulesets" ) );
rulesets.setShortDescription( NbBundle.getMessage( PMDOptionsSettingsBeanInfo.class, "HINT_rulesets" ) );
rulesets.setPropertyEditorClass( RuleSetChooserEditor.class );
descriptor[2] = rulesets;
}
catch( IntrospectionException ie ) {
ErrorManager.getDefault().notify( ie );

View File

@ -0,0 +1,112 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.0" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[355, 200]"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[300, 131]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="1" insetsRight="0" anchor="11" weightX="0.5" weightY="1.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="rulesetList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new DefaultListModel()" type="code"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[200, 200]"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="jPanel1">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="jPanel2">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="North"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout">
<Property name="verticalGap" type="int" value="5"/>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="remove">
<Properties>
<Property name="text" type="java.lang.String" value="Remove"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="removeActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="Center"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="add">
<Properties>
<Property name="text" type="java.lang.String" value="Add"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="addActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="North"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="jLabel1">
<Properties>
<Property name="text" type="java.lang.String" value="Choose the rulesets to use."/>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="0" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JCheckBox" name="stdRules">
<Properties>
<Property name="text" type="java.lang.String" value="Include PMD standard rules."/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="stdRulesActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="13" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,162 @@
/*
* RuleSetChooser.java
*
* Created on 20. februar 2003, 21:16
*/
package pmd.config.ui;
import java.beans.PropertyEditorSupport;
import javax.swing.DefaultListModel;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
/**
*
* @author ole martin mørk
*/
public class RuleSetChooser extends JPanel {
private final PropertyEditorSupport editor;
private final JFileChooser chooser = new JFileChooser();
/** Creates new form RuleSetChooser */
public RuleSetChooser(PropertyEditorSupport editor) {
this.editor = editor;
RuleSetFilter filter = new RuleSetFilter();
chooser.setFileFilter( filter );
initComponents();
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
private void initComponents() {//GEN-BEGIN:initComponents
java.awt.GridBagConstraints gridBagConstraints;
jScrollPane1 = new javax.swing.JScrollPane();
rulesetList = new javax.swing.JList();
jPanel1 = new javax.swing.JPanel();
jPanel2 = new javax.swing.JPanel();
remove = new javax.swing.JButton();
add = new javax.swing.JButton();
jLabel1 = new javax.swing.JLabel();
stdRules = new javax.swing.JCheckBox();
setLayout(new java.awt.GridBagLayout());
setPreferredSize(new java.awt.Dimension(355, 200));
jScrollPane1.setPreferredSize(new java.awt.Dimension(300, 131));
rulesetList.setModel(new DefaultListModel());
rulesetList.setMinimumSize(new java.awt.Dimension(200, 200));
jScrollPane1.setViewportView(rulesetList);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 1, 0);
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
gridBagConstraints.weightx = 0.5;
gridBagConstraints.weighty = 1.0;
add(jScrollPane1, gridBagConstraints);
jPanel1.setLayout(new java.awt.BorderLayout());
jPanel2.setLayout(new java.awt.BorderLayout(0, 5));
remove.setText("Remove");
remove.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
removeActionPerformed(evt);
}
});
jPanel2.add(remove, java.awt.BorderLayout.CENTER);
add.setText("Add");
add.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
addActionPerformed(evt);
}
});
jPanel2.add(add, java.awt.BorderLayout.NORTH);
jPanel1.add(jPanel2, java.awt.BorderLayout.NORTH);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
add(jPanel1, gridBagConstraints);
jLabel1.setText("Choose the rulesets to use.");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
add(jLabel1, gridBagConstraints);
stdRules.setText("Include PMD standard rules.");
stdRules.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
stdRulesActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
add(stdRules, gridBagConstraints);
}//GEN-END:initComponents
private void stdRulesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stdRulesActionPerformed
editor.firePropertyChange();
}//GEN-LAST:event_stdRulesActionPerformed
private void removeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeActionPerformed
int index = rulesetList.getSelectedIndex();
getListModel().removeElementAt( index );
editor.firePropertyChange();
}//GEN-LAST:event_removeActionPerformed
private void addActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addActionPerformed
int returnValue = chooser.showOpenDialog( this );
if(returnValue == JFileChooser.APPROVE_OPTION) {
if( !getListModel().contains( chooser.getSelectedFile().getAbsolutePath() ) ) {
getListModel().addElement(
chooser.getSelectedFile().getAbsolutePath() );
}
}
chooser.cancelSelection();
editor.firePropertyChange();
}//GEN-LAST:event_addActionPerformed
public DefaultListModel getListModel() {
return (DefaultListModel)rulesetList.getModel();
}
public boolean includeStandardRules() {
return stdRules.isSelected();
}
public void setIncludeStandardRules( boolean selected ) {
stdRules.setSelected( selected );
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JList rulesetList;
private javax.swing.JButton remove;
private javax.swing.JButton add;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JLabel jLabel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JPanel jPanel1;
private javax.swing.JCheckBox stdRules;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2002-2003, Ole-Martin Mørk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package pmd.config.ui;
import java.awt.Component;
import java.beans.PropertyEditorSupport;
import java.util.StringTokenizer;
import javax.swing.DefaultListModel;
import javax.swing.ListModel;
/** The PropertyEditor of the Rule property
* @author ole martin mørk
* @created 18. november 2002
*/
public class RuleSetChooserEditor extends PropertyEditorSupport {
RuleSetChooser chooser = new RuleSetChooser( this );
/**
* Returns the custom editor of the Rule property
* @return the editor
*/
public Component getCustomEditor() {
return chooser;
}
/**
* Returns true
* @return true
*/
public boolean supportsCustomEditor() {
return true;
}
/**
* Returns the selected rules
* @return the selected rules
*/
public Object getValue() {
ListModel model = chooser.getListModel();
StringBuffer buffer = new StringBuffer();
for( int i = 0; i < model.getSize(); i++ ) {
buffer.append( model.getElementAt( i ) ).append( ", " );
}
if( buffer.length() > 2 ) {
buffer.delete( buffer.length() - 2, buffer.length() );
}
buffer.append( ", " ).append( chooser.includeStandardRules() );
return buffer.toString();
}
/**
* Returns a string representation of the property value
* @return the property as text
*/
public String getAsText() {
return getValue().toString();
}
/**
* Sets the value to be edited in the editor
* @param obj The new value
*/
public void setValue( Object obj ) {
if( obj != null ) {
DefaultListModel model = chooser.getListModel();
StringTokenizer tokenizer = new StringTokenizer( obj.toString(), "," );
int tokens = tokenizer.countTokens();
for( int i = 0; i < tokens - 1 && tokenizer.hasMoreTokens(); i++ ) {
model.addElement( tokenizer.nextToken().trim() );
}
if( tokenizer.hasMoreTokens() ) {
chooser.setIncludeStandardRules(
Boolean.valueOf( tokenizer.nextToken().trim() ).equals( Boolean.TRUE ) );
}
}
}
/**
* Not implemented
* @param string the text
* @exception IllegalArgumentException never
*/
public void setAsText( String string ) throws IllegalArgumentException { }
}

View File

@ -0,0 +1,25 @@
/*
* RulesetFilter.java
*
* Created on 20. februar 2003, 22:52
*/
package pmd.config.ui;
import javax.swing.filechooser.FileFilter;
/**
*
* @author ole martin mørk
*/
public class RuleSetFilter extends FileFilter {
public boolean accept(java.io.File file) {
return file.getName().toLowerCase().endsWith( "xml" ) || file.isDirectory();
}
public String getDescription() {
return "RuleSet(*.xml)";
}
}

View File

@ -0,0 +1,80 @@
/*
* RuleClassLoader.java
*
* Created on 21. februar 2003, 00:31
*/
package pmd.custom;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.StringTokenizer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import pmd.config.PMDOptionsSettings;
/**
* @author ole martin mørk
* @created 21. februar 2003
*/
public class RuleClassLoader extends ClassLoader {
/**
* Creates a new instance of RuleClassLoader
*
* @param parent Description of the Parameter
*/
public RuleClassLoader( ClassLoader parent ) {
super( parent );
}
/**
* Description of the Method
*
* @param name Description of the Parameter
* @return Description of the Return Value
*/
protected Class findClass( String name ) {
System.out.println( "Loading class " + name );
String className = name.replace( '.', '/' );
className += ".class";
String classPath = PMDOptionsSettings.getDefault().getClasspath();
StringTokenizer tokens = new StringTokenizer( classPath, ";" );
try {
while( tokens.hasMoreTokens() ) {
File jar = new File( tokens.nextToken() );
JarFile jarFile = new JarFile( jar, false );
JarEntry entry = jarFile.getJarEntry( className );
System.out.println( entry );
if( entry != null ) {
BufferedInputStream stream = new BufferedInputStream( jarFile.getInputStream( entry ) );
byte buffer[] = new byte[stream.available()];
stream.read( buffer, 0, buffer.length );
return defineClass( name, buffer, 0, buffer.length );
}
}
}
catch( IOException e ) {
return null;
}
return null;
}
/**
* Description of the Method
*
* @param args Description of the Parameter
* @exception Exception Description of the Exception
*/
public static void main( String args[] ) throws Exception {
Class clazz = Class.forName( "net.sourceforge.pmd.Report", true, new RuleClassLoader( RuleClassLoader.class.getClassLoader() ) );
Object o = clazz.newInstance();
Method method = clazz.getMethod( "hasMetrics", null );
System.out.println( method.invoke( o, null ) );
}
}