@@ -53,7 +53,7 @@ public class CheckstyleAuditListener implements AuditListener, BatchExtension { | |||
Rule rule = ruleFinder.findByKey(CheckstyleConstants.REPOSITORY_KEY, ruleKey); | |||
if (rule != null) { | |||
initResource(event); | |||
Violation violation = new Violation(rule, currentResource) | |||
Violation violation = Violation.create(rule, currentResource) | |||
.setLineId(getLineId(event)) | |||
.setMessage(getMessage(event)); | |||
context.saveViolation(violation); |
@@ -60,7 +60,7 @@ public class FindbugsSensor implements Sensor, DependsUponMavenPlugin, Generates | |||
Rule rule = ruleFinder.findByKey(FindbugsConstants.REPOSITORY_KEY, fbViolation.getType()); | |||
JavaFile resource = new JavaFile(fbViolation.getSonarJavaFileKey()); | |||
if (context.getResource(resource) != null) { | |||
Violation violation = new Violation(rule, resource).setLineId(fbViolation.getStart()).setMessage(fbViolation.getLongMessage()); | |||
Violation violation = Violation.create(rule, resource).setLineId(fbViolation.getStart()).setMessage(fbViolation.getLongMessage()); | |||
context.saveViolation(violation); | |||
} | |||
} |
@@ -72,7 +72,7 @@ public class PmdViolationsXmlParserTest { | |||
verify(context, times(30)).saveViolation(argThat(new IsViolationOnJavaClass())); | |||
verify(context, times(4)).saveViolation(argThat(new IsViolationOnJavaClass(new JavaFile("ch.hortis.sonar.mvn.ClassWithComments")))); | |||
Violation wanted = new Violation(null, new JavaFile("ch.hortis.sonar.mvn.ClassWithComments")) | |||
Violation wanted = Violation.create((Rule)null, new JavaFile("ch.hortis.sonar.mvn.ClassWithComments")) | |||
.setMessage("Avoid unused local variables such as 'toto'.") | |||
.setLineId(22); | |||
verify(context, times(1)).saveViolation(argThat(new IsViolation(wanted))); |
@@ -134,7 +134,6 @@ | |||
<skip>true</skip> | |||
</configuration> | |||
</plugin> | |||
</plugins> | |||
</build> | |||
</project> |
@@ -52,7 +52,7 @@ public class ViolationsDao { | |||
List<RuleFailureModel> models = session.getResults(RuleFailureModel.class, "snapshotId", snapshotId); | |||
List<Violation> violations = new ArrayList<Violation>(); | |||
for (RuleFailureModel model : models) { | |||
Violation violation = new Violation(model.getRule(), resource); | |||
Violation violation = Violation.create(model.getRule(), resource); | |||
violation.setLineId(model.getLine()); | |||
violation.setMessage(model.getMessage()); | |||
violation.setPriority(model.getPriority()); |
@@ -164,7 +164,7 @@ public abstract class AbstractViolationsStaxParser { | |||
Rule rule = getRule(violationCursor); | |||
Integer line = getLineIndex(violationCursor); | |||
if (rule != null && resource != null) { | |||
Violation violation = new Violation(rule, resource) | |||
Violation violation = Violation.create(rule, resource) | |||
.setLineId(line) | |||
.setMessage(messageFor(violationCursor)); | |||
context.saveViolation(violation); |
@@ -96,7 +96,7 @@ public class MessageDispatcher { | |||
public void log(Resource resource, Message message) { | |||
Object checker = message.getChecker(); | |||
Check check = getCheck(checker); | |||
Violation violation = new Violation(new Rule(check.getRepositoryKey(), check.getTemplateKey()), resource); | |||
Violation violation = Violation.create(new Rule(check.getRepositoryKey(), check.getTemplateKey()), resource); | |||
violation.setLineId(message.getLine()); | |||
violation.setMessage(message.getText(Locale.ENGLISH)); | |||
violation.setPriority(RulePriority.fromCheckPriority(check.getPriority())); |
@@ -0,0 +1,31 @@ | |||
/* | |||
* Sonar, open source software quality management tool. | |||
* Copyright (C) 2009 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* Sonar is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* Sonar 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 | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with Sonar; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||
*/ | |||
package org.sonar.api; | |||
import java.util.Collection; | |||
/** | |||
* @since 2.3 | |||
*/ | |||
public interface ExtensionProvider { | |||
Collection provide(); | |||
} |
@@ -20,10 +20,10 @@ | |||
package org.sonar.api.profiles; | |||
import org.sonar.api.rules.Rule; | |||
import org.sonar.api.rules.RuleAnnotationUtils; | |||
import org.sonar.api.rules.RuleFinder; | |||
import org.sonar.api.rules.RulePriority; | |||
import org.sonar.api.utils.ValidationMessages; | |||
import org.sonar.check.AnnotationIntrospector; | |||
import org.sonar.check.BelongsToProfile; | |||
import java.util.Collection; | |||
@@ -61,7 +61,7 @@ public abstract class AnnotationProfileDefinition extends ProfileDefinition { | |||
private void registerRule(Class aClass, BelongsToProfile belongsToProfile, RulesProfile profile, ValidationMessages validation) { | |||
if (belongsToProfile != null) { | |||
String ruleKey = AnnotationIntrospector.getCheckKey(aClass); | |||
String ruleKey = RuleAnnotationUtils.getRuleKey(aClass); | |||
Rule rule = ruleFinder.findByKey(repositoryKey, ruleKey); | |||
if (rule == null) { | |||
validation.addErrorText("Rule not found: [repository=" + repositoryKey + ", key=" + ruleKey + "]"); |
@@ -19,77 +19,30 @@ | |||
*/ | |||
package org.sonar.api.rules; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.check.AnnotationIntrospector; | |||
import java.lang.reflect.Field; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.List; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.utils.AnnotationUtils; | |||
import org.sonar.check.Check; | |||
/** | |||
* @since 2.3 | |||
*/ | |||
public final class RuleAnnotationUtils { | |||
private static final Logger LOG = LoggerFactory.getLogger(RuleAnnotationUtils.class); | |||
private RuleAnnotationUtils() { | |||
// only static methods | |||
} | |||
public static List<Rule> readAnnotatedClasses(Collection<Class> annotatedClasses) { | |||
List<Rule> rules = new ArrayList<Rule>(); | |||
if (annotatedClasses != null) { | |||
for (Class annotatedClass : annotatedClasses) { | |||
Rule rule = readAnnotatedClass(annotatedClass); | |||
if (rule != null) { | |||
rules.add(rule); | |||
} | |||
} | |||
} | |||
return rules; | |||
} | |||
public static Rule readAnnotatedClass(Class annotatedClass) { | |||
org.sonar.check.Check checkAnnotation = AnnotationIntrospector.getCheckAnnotation(annotatedClass); | |||
if (checkAnnotation == null) { | |||
LOG.warn("The class " + annotatedClass.getCanonicalName() + " is not a rule. It should be annotated with " + org.sonar.check.Check.class); | |||
return null; | |||
} | |||
Rule rule = toRule(annotatedClass, checkAnnotation); | |||
Field[] fields = annotatedClass.getDeclaredFields(); | |||
if (fields != null) { | |||
for (Field field : fields) { | |||
createParam(rule, field); | |||
} | |||
} | |||
return rule; | |||
} | |||
private static Rule toRule(Class annotatedClass, org.sonar.check.Check annotation) { | |||
String key = AnnotationIntrospector.getCheckKey(annotatedClass); | |||
Rule rule = Rule.create(); | |||
rule.setKey(key); | |||
rule.setName(annotation.title()); | |||
rule.setDescription(annotation.description()); | |||
rule.setRulesCategory(new RulesCategory(annotation.isoCategory().name())); | |||
rule.setPriority(RulePriority.fromCheckPriority(annotation.priority())); | |||
return rule; | |||
} | |||
private static void createParam(Rule rule, Field field) { | |||
org.sonar.check.CheckProperty propertyAnnotation = field.getAnnotation(org.sonar.check.CheckProperty.class); | |||
if (propertyAnnotation != null) { | |||
String fieldKey = propertyAnnotation.key(); | |||
if (fieldKey==null || "".equals(fieldKey)) { | |||
fieldKey = field.getName(); | |||
public static String getRuleKey(Class annotatedClass) { | |||
String key = null; | |||
org.sonar.check.Rule ruleAnnotation = AnnotationUtils.getClassAnnotation(annotatedClass, org.sonar.check.Rule.class); | |||
if (ruleAnnotation != null) { | |||
key = ruleAnnotation.key(); | |||
} else { | |||
Check checkAnnotation = AnnotationUtils.getClassAnnotation(annotatedClass, Check.class); | |||
if (checkAnnotation != null) { | |||
key = checkAnnotation.key(); | |||
} | |||
RuleParam param = rule.createParameter(fieldKey); | |||
param.setDescription(propertyAnnotation.description()); | |||
} | |||
return StringUtils.defaultIfEmpty(key, annotatedClass.getCanonicalName()); | |||
} | |||
} |
@@ -38,7 +38,9 @@ public class Violation { | |||
/** | |||
* Creates of a violation from a rule. Will need to define the resource later on | |||
* @deprecated since 2.3. Use the factory method create() | |||
*/ | |||
@Deprecated | |||
public Violation(Rule rule) { | |||
this.rule = rule; | |||
} | |||
@@ -48,7 +50,9 @@ public class Violation { | |||
* | |||
* @param rule the rule that has been violated | |||
* @param resource the resource the violation should be attached to | |||
* @deprecated since 2.3. Use the factory method create() | |||
*/ | |||
@Deprecated | |||
public Violation(Rule rule, Resource resource) { | |||
this.resource = resource; | |||
this.rule = rule; | |||
@@ -118,7 +122,9 @@ public class Violation { | |||
* Sets the violation priority | |||
* | |||
* @return the current object | |||
* @deprecated since 2.3. The priority is set by the quality profile. | |||
*/ | |||
@Deprecated | |||
public Violation setPriority(RulePriority priority) { | |||
this.priority = priority; | |||
return this; | |||
@@ -170,4 +176,12 @@ public class Violation { | |||
public String toString() { | |||
return ReflectionToStringBuilder.toString(this); | |||
} | |||
public static Violation create(ActiveRule activeRule, Resource resource) { | |||
return new Violation(activeRule.getRule()).setResource(resource); | |||
} | |||
public static Violation create(Rule rule, Resource resource) { | |||
return new Violation(rule).setResource(resource); | |||
} | |||
} |
@@ -22,7 +22,10 @@ package org.sonar.api.resources; | |||
import org.apache.commons.io.FileUtils; | |||
import static org.hamcrest.CoreMatchers.is; | |||
import static org.junit.Assert.*; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.TemporaryFolder; | |||
import java.io.File; | |||
import java.io.IOException; | |||
@@ -30,6 +33,10 @@ import java.util.Arrays; | |||
import java.util.List; | |||
public class JavaFileTest { | |||
@Rule | |||
public TemporaryFolder tempFolder = new TemporaryFolder(); | |||
@Test | |||
public void testNewClass() { | |||
JavaFile javaClass = new JavaFile("org.foo.bar.Hello", false); | |||
@@ -127,8 +134,9 @@ public class JavaFileTest { | |||
assertEquals("onelevel.MyFile", clazz.getKey()); | |||
assertEquals("onelevel", clazz.getParent().getKey()); | |||
List<File> sources = Arrays.asList(newDir("sources")); | |||
JavaFile javaFile = JavaFile.fromAbsolutePath(absPath("sources/onelevel/MyFile.java"), sources, false); | |||
File sourceDir = newDir("sources"); | |||
List<File> sources = Arrays.asList(sourceDir); | |||
JavaFile javaFile = JavaFile.fromAbsolutePath(absPath(sourceDir, "onelevel/MyFile.java"), sources, false); | |||
assertEquals("onelevel.MyFile", javaFile.getKey()); | |||
assertEquals("MyFile", javaFile.getName()); | |||
assertEquals("onelevel", javaFile.getParent().getKey()); | |||
@@ -139,8 +147,10 @@ public class JavaFileTest { | |||
@Test | |||
public void shouldResolveClassFromAbsolutePath() throws IOException { | |||
List<File> sources = Arrays.asList(newDir("source1"), newDir("source2")); | |||
JavaFile javaFile = JavaFile.fromAbsolutePath(absPath("source2/foo/bar/MyFile.java"), sources, false); | |||
File sources1 = newDir("source1"); | |||
File sources2 = newDir("source2"); | |||
List<File> sources = Arrays.asList(sources1, sources2); | |||
JavaFile javaFile = JavaFile.fromAbsolutePath(absPath(sources2, "foo/bar/MyFile.java"), sources, false); | |||
assertThat("foo.bar.MyFile", is(javaFile.getKey())); | |||
assertThat(javaFile.getLongName(), is("foo.bar.MyFile")); | |||
assertThat(javaFile.getName(), is("MyFile")); | |||
@@ -149,9 +159,11 @@ public class JavaFileTest { | |||
@Test | |||
public void shouldResolveFromAbsolutePathEvenIfDefaultPackage() throws IOException { | |||
List<File> sources = Arrays.asList(newDir("source1"), newDir("source2")); | |||
File source1 = newDir("source1"); | |||
File source2 = newDir("source2"); | |||
List<File> sources = Arrays.asList(source1, source2); | |||
JavaFile javaClass = JavaFile.fromAbsolutePath(absPath("source1/MyClass.java"), sources, false); | |||
JavaFile javaClass = JavaFile.fromAbsolutePath(absPath(source1, "MyClass.java"), sources, false); | |||
assertEquals(JavaPackage.DEFAULT_PACKAGE_NAME + ".MyClass", javaClass.getKey()); | |||
assertEquals("MyClass", javaClass.getName()); | |||
@@ -160,14 +172,16 @@ public class JavaFileTest { | |||
@Test | |||
public void shouldResolveOnlyJavaFromAbsolutePath() throws IOException { | |||
List<File> sources = Arrays.asList(newDir("source1")); | |||
assertNull(JavaFile.fromAbsolutePath(absPath("source1/foo/bar/my_file.sql"), sources, false)); | |||
File source1 = newDir("source1"); | |||
List<File> sources = Arrays.asList(source1); | |||
assertNull(JavaFile.fromAbsolutePath(absPath(source1, "foo/bar/my_file.sql"), sources, false)); | |||
} | |||
@Test | |||
public void shouldNotFailWhenResolvingUnknownClassFromAbsolutePath() throws IOException { | |||
List<File> sources = Arrays.asList(newDir("source1")); | |||
assertNull(JavaFile.fromAbsolutePath(absPath("/home/other/src/main/java/foo/bar/MyClass.java"), sources, false)); | |||
File source1 = newDir("source1"); | |||
List<File> sources = Arrays.asList(source1); | |||
assertNull(JavaFile.fromAbsolutePath("/home/other/src/main/java/foo/bar/MyClass.java", sources, false)); | |||
} | |||
@Test | |||
@@ -211,14 +225,11 @@ public class JavaFileTest { | |||
} | |||
private File newDir(String relativePath) throws IOException { | |||
File target = new File("target", relativePath); | |||
FileUtils.forceMkdir(target); | |||
FileUtils.cleanDirectory(target); | |||
return target; | |||
private File newDir(String dirName) throws IOException { | |||
return tempFolder.newFolder(dirName); | |||
} | |||
private String absPath(String relativePath) throws IOException { | |||
return new File("target", relativePath).getCanonicalPath(); | |||
private String absPath(File dir, String filePath) throws IOException { | |||
return new File(dir, filePath).getPath(); | |||
} | |||
} |
@@ -19,9 +19,8 @@ | |||
*/ | |||
package org.sonar.api.rules; | |||
import org.sonar.check.Check; | |||
import org.sonar.check.IsoCategory; | |||
@Check(title ="Annotated Check", description = "Description", isoCategory = IsoCategory.Reliability) | |||
@org.sonar.check.Rule(name ="Annotated Check", description = "Description", isoCategory = IsoCategory.Reliability) | |||
public class AnnotatedCheck { | |||
} |
@@ -19,17 +19,16 @@ | |||
*/ | |||
package org.sonar.api.rules; | |||
import org.sonar.check.Check; | |||
import org.sonar.check.CheckProperty; | |||
import org.sonar.check.IsoCategory; | |||
import org.sonar.check.RuleProperty; | |||
@Check(key = "overriden_key",title ="Check with parameters", description = "Has parameters", isoCategory = IsoCategory.Efficiency) | |||
@org.sonar.check.Rule(key = "overridden_key", name = "Check with parameters", description = "Has parameters", isoCategory = IsoCategory.Efficiency) | |||
public class AnnotatedCheckWithParameters { | |||
@CheckProperty(description ="Maximum value") | |||
@RuleProperty(description = "Maximum value") | |||
private String max; | |||
@CheckProperty(key = "overidden_min", description ="Minimum value") | |||
@RuleProperty(key = "overridden_min", description = "Minimum value") | |||
protected String min; | |||
private int nonConfigurableProperty; |
@@ -0,0 +1,27 @@ | |||
/* | |||
* Sonar, open source software quality management tool. | |||
* Copyright (C) 2009 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* Sonar is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* Sonar 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 | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with Sonar; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||
*/ | |||
package org.sonar.api.rules; | |||
import org.sonar.check.Check; | |||
import org.sonar.check.IsoCategory; | |||
@Check(title ="Annotated Check", description = "Description", isoCategory = IsoCategory.Reliability) | |||
public class DeprecatedAnnotatedCheck { | |||
} |
@@ -19,46 +19,28 @@ | |||
*/ | |||
package org.sonar.api.rules; | |||
import org.hamcrest.core.Is; | |||
import org.junit.Test; | |||
import static org.hamcrest.CoreMatchers.nullValue; | |||
import static org.hamcrest.core.Is.is; | |||
import static org.hamcrest.core.IsNot.not; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertThat; | |||
public class RuleAnnotationUtilsTest { | |||
@Test | |||
public void readAnnotatedClassWithoutParameters() { | |||
Rule rule = RuleAnnotationUtils.readAnnotatedClass(AnnotatedCheck.class); | |||
assertNotNull(rule); | |||
assertThat(rule.getKey(), is(AnnotatedCheck.class.getName())); | |||
assertThat(rule.getName(), is("Annotated Check")); | |||
assertThat(rule.getConfigKey(), nullValue()); | |||
assertThat(rule.getParams().size(), is(0)); | |||
assertThat(rule.getDescription(), is("Description")); | |||
assertThat(rule.getCardinality(), Is.is(Rule.Cardinality.SINGLE)); | |||
assertThat(rule.getRulesCategory().getName(), Is.is(Iso9126RulesCategories.RELIABILITY.getName())); | |||
public void defaultKeyShouldBeTheClassName() { | |||
String key = RuleAnnotationUtils.getRuleKey(AnnotatedCheck.class); | |||
assertThat(key, is(AnnotatedCheck.class.getName())); | |||
} | |||
@Test | |||
public void ruleKeyCanBeOverridden() { | |||
Rule rule = RuleAnnotationUtils.readAnnotatedClass(AnnotatedCheckWithParameters.class); | |||
assertNotNull(rule); | |||
assertThat(rule.getKey(), is("overriden_key")); | |||
public void shouldGetKeyFromDeprecatedCheckAnnotation() { | |||
String key = RuleAnnotationUtils.getRuleKey(DeprecatedAnnotatedCheck.class); | |||
assertThat(key, is(DeprecatedAnnotatedCheck.class.getName())); | |||
} | |||
@Test | |||
public void readAnnotatedClassWithParameters() { | |||
Rule rule = RuleAnnotationUtils.readAnnotatedClass(AnnotatedCheckWithParameters.class); | |||
assertNotNull(rule); | |||
assertThat(rule.getParams().size(), is(2)); | |||
assertThat(rule.getParam("max"), not(nullValue())); | |||
assertThat(rule.getParam("max").getDescription(), is("Maximum value")); | |||
assertThat(rule.getParam("min"), nullValue()); | |||
assertThat(rule.getParam("overidden_min"), not(nullValue())); | |||
assertThat(rule.getParam("overidden_min").getDescription(), is("Minimum value")); | |||
@Test | |||
public void shouldGetKey() { | |||
String key = RuleAnnotationUtils.getRuleKey(AnnotatedCheckWithParameters.class); | |||
assertThat(key, is("overridden_key")); | |||
} | |||
} |