aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersisterTest.java2
-rw-r--r--sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportComponent.java31
-rw-r--r--sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/resource/ReportComponentsTest.java6
-rw-r--r--sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/resource/ReportResourceTest/expected.json2
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/DefaultResourcePersister.java8
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java4
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/report/ComponentsPublisher.java25
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/report/PublishReportJob.java2
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/FileHashesPersisterTest.java2
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/ResourceCacheTest.java4
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java2
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/report/ComponentsPublisherTest.java84
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/PreviousFileHashLoaderTest.java2
-rw-r--r--sonar-batch/src/test/resources/org/sonar/batch/report/ComponentsPublisherTest/expected.json59
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/resources/Resource.java5
16 files changed, 221 insertions, 19 deletions
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersisterTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersisterTest.java
index 4f9ac63c11f..1c271fb2b72 100644
--- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersisterTest.java
+++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/TimeMachineConfigurationPersisterTest.java
@@ -49,7 +49,7 @@ public class TimeMachineConfigurationPersisterTest extends AbstractDbUnitTestCas
ResourceCache resourceCache = new ResourceCache();
Project project = new Project("foo");
- resourceCache.add(project, projectSnapshot);
+ resourceCache.add(project, null, projectSnapshot);
TimeMachineConfigurationPersister persister = new TimeMachineConfigurationPersister(timeMachineConfiguration, resourceCache, getSession());
diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportComponent.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportComponent.java
index ef24686d4b2..578cf92d73d 100644
--- a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportComponent.java
+++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/resource/ReportComponent.java
@@ -19,6 +19,8 @@
*/
package org.sonar.batch.protocol.output.resource;
+import javax.annotation.CheckForNull;
+
import java.util.ArrayList;
import java.util.Collection;
@@ -28,7 +30,9 @@ public class ReportComponent {
PRJ,
MOD,
DIR,
- FIL
+ FIL,
+ VIEW,
+ SUBVIEW
}
private long batchId;
@@ -37,6 +41,9 @@ public class ReportComponent {
private String path;
private String name;
private Type type;
+ // Only for files
+ private Boolean isTest;
+ private String languageKey;
private Collection<ReportComponent> children = new ArrayList<ReportComponent>();
@@ -94,6 +101,28 @@ public class ReportComponent {
return type;
}
+ public ReportComponent setTest(Boolean isTest) {
+ this.isTest = isTest;
+ return this;
+ }
+
+ /**
+ * @return null when not a file
+ */
+ @CheckForNull
+ public Boolean isTest() {
+ return isTest;
+ }
+
+ public ReportComponent setLanguageKey(String languageKey) {
+ this.languageKey = languageKey;
+ return this;
+ }
+
+ public String languageKey() {
+ return languageKey;
+ }
+
public ReportComponent addChild(ReportComponent child) {
this.children.add(child);
return this;
diff --git a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/resource/ReportComponentsTest.java b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/resource/ReportComponentsTest.java
index 085a0c0f65a..b3b989aa8f8 100644
--- a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/resource/ReportComponentsTest.java
+++ b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/resource/ReportComponentsTest.java
@@ -64,7 +64,9 @@ public class ReportComponentsTest {
.setName("Foo.java")
.setSnapshotId(444)
.setPath("Foo.java")
- .setType(Type.FIL);
+ .setType(Type.FIL)
+ .setTest(true)
+ .setLanguageKey("java");
dir.addChild(file);
res.setRoot(root);
@@ -89,6 +91,8 @@ public class ReportComponentsTest {
assertThat(root.path()).isNull();
assertThat(root.type()).isEqualTo(Type.PRJ);
assertThat(root.children()).hasSize(1);
+ assertThat(root.isTest()).isNull();
+ assertThat(root.languageKey()).isNull();
}
}
diff --git a/sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/resource/ReportResourceTest/expected.json b/sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/resource/ReportResourceTest/expected.json
index 4c642a06ba0..581bbc5ea23 100644
--- a/sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/resource/ReportResourceTest/expected.json
+++ b/sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/output/resource/ReportResourceTest/expected.json
@@ -30,6 +30,8 @@
"path": "Foo.java",
"name": "Foo.java",
"type": "FIL",
+ "languageKey": "java",
+ "isTest": true,
"children": []
}
]
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultResourcePersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultResourcePersister.java
index b7d5418555c..5c74459778a 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultResourcePersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultResourcePersister.java
@@ -65,12 +65,12 @@ public final class DefaultResourcePersister implements ResourcePersister {
BatchResource batchResource = resourceCache.get(project.getEffectiveKey());
if (batchResource == null) {
Snapshot snapshot = persistProject(project, parent);
- addToCache(project, snapshot);
+ addToCache(project, project.getParent(), snapshot);
}
}
- private BatchResource addToCache(Resource resource, Snapshot snapshot) {
- return resourceCache.add(resource, snapshot);
+ private BatchResource addToCache(Resource resource, @Nullable Resource parent, Snapshot snapshot) {
+ return resourceCache.add(resource, parent, snapshot);
}
private Snapshot persistProject(Project project, @Nullable Project parent) {
@@ -124,7 +124,7 @@ public final class DefaultResourcePersister implements ResourcePersister {
BatchResource batchResource = resourceCache.get(resource.getEffectiveKey());
if (batchResource == null || ResourceUtils.isLibrary(resource)) {
Snapshot s = persist(project, resource, parent);
- batchResource = addToCache(resource, s);
+ batchResource = addToCache(resource, parent, s);
}
return batchResource;
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java b/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java
index 088a50de84c..01add749f84 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java
@@ -28,6 +28,7 @@ import org.sonar.api.resources.Library;
import org.sonar.api.resources.Resource;
import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Map;
@@ -52,10 +53,9 @@ public class ResourceCache implements BatchComponent {
}
}
- public BatchResource add(Resource resource, Snapshot s) {
+ public BatchResource add(Resource resource, @Nullable Resource parentResource, Snapshot s) {
String componentKey = resource.getEffectiveKey();
Preconditions.checkState(!Strings.isNullOrEmpty(componentKey), "Missing resource effective key");
- Resource parentResource = resource.getParent();
BatchResource parent = parentResource != null ? get(parentResource.getEffectiveKey()) : null;
BatchResource batchResource = new BatchResource((long) resources.size() + 1, resource, s, parent);
if (!(resource instanceof Library)) {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/ComponentsPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/ComponentsPublisher.java
index f5011b50648..85f5081d29f 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/report/ComponentsPublisher.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/ComponentsPublisher.java
@@ -21,6 +21,7 @@ package org.sonar.batch.report;
import org.apache.commons.io.FileUtils;
import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.resources.ResourceUtils;
import org.sonar.batch.index.BatchResource;
@@ -46,6 +47,7 @@ public class ComponentsPublisher implements ReportPublisher {
ReportComponents components = new ReportComponents();
BatchResource rootProject = resourceCache.get(reactor.getRoot().getKeyWithBranch());
components.setRoot(buildResourceForReport(rootProject));
+ components.setAnalysisDate(((Project) rootProject.resource()).getAnalysisDate());
File resourcesFile = new File(reportDir, "components.json");
FileUtils.write(resourcesFile, components.toJson());
}
@@ -56,15 +58,30 @@ public class ComponentsPublisher implements ReportPublisher {
.setBatchId(batchResource.batchId())
.setSnapshotId(batchResource.snapshotId())
.setId(r.getId())
- .setName(r.getName())
+ .setName(getName(r))
.setPath(r.getPath())
- .setType(getType(r));
+ .setType(getType(r))
+ .setLanguageKey(getLanguageKey(r))
+ .setTest(isTest(r));
for (BatchResource child : batchResource.children()) {
result.addChild(buildResourceForReport(child));
}
return result;
}
+ private Boolean isTest(Resource r) {
+ return ResourceUtils.isFile(r) ? ResourceUtils.isUnitTestClass(r) : null;
+ }
+
+ private String getLanguageKey(Resource r) {
+ return ResourceUtils.isFile(r) ? r.getLanguage().getKey() : null;
+ }
+
+ private String getName(Resource r) {
+ // Don't return name for directories and files since it can be guessed from the path
+ return (ResourceUtils.isFile(r) || ResourceUtils.isDirectory(r)) ? null : r.getName();
+ }
+
private ReportComponent.Type getType(Resource r) {
if (ResourceUtils.isFile(r)) {
return ReportComponent.Type.FIL;
@@ -74,6 +91,10 @@ public class ComponentsPublisher implements ReportPublisher {
return ReportComponent.Type.MOD;
} else if (ResourceUtils.isRootProject(r)) {
return ReportComponent.Type.PRJ;
+ } else if (ResourceUtils.isView(r)) {
+ return ReportComponent.Type.VIEW;
+ } else if (ResourceUtils.isSubview(r)) {
+ return ReportComponent.Type.SUBVIEW;
}
throw new IllegalArgumentException("Unknow resource type: " + r);
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/PublishReportJob.java b/sonar-batch/src/main/java/org/sonar/batch/report/PublishReportJob.java
index 16b5dbd59d7..fdaa2843e9a 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/report/PublishReportJob.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/PublishReportJob.java
@@ -111,7 +111,7 @@ public class PublishReportJob implements BatchComponent {
request.trustAllHosts();
request.header("User-Agent", String.format("SonarQube %s", server.getVersion()));
request.basic(serverClient.getLogin(), serverClient.getPassword());
- request.part("report", report);
+ request.part("report", null, "application/octet-stream", report);
if (!request.ok()) {
int responseCode = request.code();
if (responseCode == 401) {
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/FileHashesPersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/FileHashesPersisterTest.java
index 3e6c4866245..c66809ec396 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/FileHashesPersisterTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/FileHashesPersisterTest.java
@@ -57,7 +57,7 @@ public class FileHashesPersisterTest extends AbstractDaoTestCase {
Snapshot snapshot = new Snapshot();
snapshot.setId(100);
snapshot.setResourceId(200);
- resourceCache.add(new Project("myProject").setId(200), snapshot);
+ resourceCache.add(new Project("myProject").setId(200), null, snapshot);
data = new ComponentDataCache(caches);
data.setStringData("myProject", SnapshotDataTypes.FILE_HASHES, "org/struts/Action.java=123ABC");
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/ResourceCacheTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/ResourceCacheTest.java
index d59709a0bd6..bc4330f8734 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/ResourceCacheTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/ResourceCacheTest.java
@@ -33,7 +33,7 @@ public class ResourceCacheTest {
ResourceCache cache = new ResourceCache();
String componentKey = "struts:src/org/struts/Action.java";
Resource resource = new File("org/struts/Action.java").setEffectiveKey(componentKey);
- cache.add(resource, new Snapshot());
+ cache.add(resource, null, new Snapshot());
assertThat(cache.get(componentKey).resource()).isSameAs(resource);
assertThat(cache.get("other")).isNull();
@@ -44,7 +44,7 @@ public class ResourceCacheTest {
ResourceCache cache = new ResourceCache();
Resource resource = new File("org/struts/Action.java").setEffectiveKey(null);
try {
- cache.add(resource, new Snapshot());
+ cache.add(resource, null, new Snapshot());
fail();
} catch (IllegalStateException e) {
// success
diff --git a/sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java b/sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java
index 63a11312309..f323737ca37 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/qualitygate/QualityGateVerifierTest.java
@@ -95,7 +95,7 @@ public class QualityGateVerifierTest {
project = new Project("foo");
resourceCache = new ResourceCache();
- resourceCache.add(project, snapshot);
+ resourceCache.add(project, null, snapshot);
verifier = new QualityGateVerifier(qualityGate, resourceCache, periods, i18n, durations);
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/report/ComponentsPublisherTest.java b/sonar-batch/src/test/java/org/sonar/batch/report/ComponentsPublisherTest.java
new file mode 100644
index 00000000000..d5a700b9d8f
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/report/ComponentsPublisherTest.java
@@ -0,0 +1,84 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.report;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.resources.Directory;
+import org.sonar.api.resources.Java;
+import org.sonar.api.resources.Project;
+import org.sonar.batch.index.ResourceCache;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+
+public class ComponentsPublisherTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Test
+ public void testComponentPublisher() throws Exception {
+ ProjectReactor reactor = new ProjectReactor(ProjectDefinition.create().setKey("foo"));
+ ResourceCache resourceCache = new ResourceCache();
+ ComponentsPublisher publisher = new ComponentsPublisher(reactor, resourceCache);
+
+ Project root = new Project("foo").setName("Root project").setAnalysisDate(new SimpleDateFormat("dd/MM/yyyy").parse("12/12/2012"));
+ root.setId(1);
+ resourceCache.add(root, null, new Snapshot().setId(11));
+ Project module1 = new Project("module1").setName("Module1");
+ module1.setParent(root);
+ module1.setId(2);
+ resourceCache.add(module1, root, new Snapshot().setId(12));
+ Directory dir1 = Directory.create("src");
+ dir1.setEffectiveKey("foo:src");
+ dir1.setId(3);
+ resourceCache.add(dir1, module1, new Snapshot().setId(13));
+ org.sonar.api.resources.File mainFile = org.sonar.api.resources.File.create("src/Foo.java", "Foo.java", Java.INSTANCE, false);
+ mainFile.setEffectiveKey("foo:src/Foo.java");
+ mainFile.setId(4);
+ resourceCache.add(mainFile, dir1, new Snapshot().setId(14));
+ Directory dir2 = Directory.create("test");
+ dir2.setEffectiveKey("foo:test");
+ dir2.setId(5);
+ resourceCache.add(dir2, module1, new Snapshot().setId(15));
+ org.sonar.api.resources.File testFile = org.sonar.api.resources.File.create("test/FooTest.java", "FooTest.java", Java.INSTANCE, true);
+ testFile.setEffectiveKey("foo:test/FooTest.java");
+ testFile.setId(6);
+ resourceCache.add(testFile, dir2, new Snapshot().setId(16));
+
+ File exportDir = temp.newFolder();
+ publisher.export(exportDir);
+
+ System.out.println(FileUtils.readFileToString(new File(exportDir, "components.json")));
+
+ JSONAssert
+ .assertEquals(
+ IOUtils.toString(this.getClass().getResourceAsStream("ComponentsPublisherTest/expected.json"), "UTF-8"),
+ FileUtils.readFileToString(new File(exportDir, "components.json")), true);
+ }
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/PreviousFileHashLoaderTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/PreviousFileHashLoaderTest.java
index 98664860bae..86fa1d726b5 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/PreviousFileHashLoaderTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/PreviousFileHashLoaderTest.java
@@ -59,7 +59,7 @@ public class PreviousFileHashLoaderTest {
@Before
public void prepare() {
resourceCache = new ResourceCache();
- resourceCache.add(project, snapshot);
+ resourceCache.add(project, null, snapshot);
loader = new PreviousFileHashLoader(project, resourceCache, snapshotDataDao, pastSnapshotFinder);
}
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/report/ComponentsPublisherTest/expected.json b/sonar-batch/src/test/resources/org/sonar/batch/report/ComponentsPublisherTest/expected.json
new file mode 100644
index 00000000000..09d60b6c0dd
--- /dev/null
+++ b/sonar-batch/src/test/resources/org/sonar/batch/report/ComponentsPublisherTest/expected.json
@@ -0,0 +1,59 @@
+{
+ "analysisDate": "2012-12-12T00:00:00+0100",
+ "root": {
+ "batchId": 1,
+ "id": 1,
+ "snapshotId": 11,
+ "name": "Root project",
+ "type": "PRJ",
+ "children": [
+ {
+ "batchId": 2,
+ "id": 2,
+ "snapshotId": 12,
+ "name": "Module1",
+ "type": "MOD",
+ "children": [
+ {
+ "batchId": 3,
+ "id": 3,
+ "snapshotId": 13,
+ "path": "src",
+ "type": "DIR",
+ "children": [
+ {
+ "batchId": 4,
+ "id": 4,
+ "snapshotId": 14,
+ "path": "src/Foo.java",
+ "type": "FIL",
+ "isTest": false,
+ "languageKey": "java",
+ "children": []
+ }
+ ]
+ },
+ {
+ "batchId": 5,
+ "id": 5,
+ "snapshotId": 15,
+ "path": "test",
+ "type": "DIR",
+ "children": [
+ {
+ "batchId": 6,
+ "id": 6,
+ "snapshotId": 16,
+ "path": "test/FooTest.java",
+ "type": "FIL",
+ "isTest": true,
+ "languageKey": "java",
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java
index bc866693f9b..950eb020e2d 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java
@@ -26,6 +26,7 @@ import org.sonar.api.CoreProperties;
import org.sonar.api.component.Component;
import org.sonar.api.config.Settings;
+import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import java.util.ArrayList;
@@ -323,6 +324,7 @@ public class Project extends Resource implements Component {
return false;
}
+ @CheckForNull
@Override
public Project getParent() {
return parent;
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Resource.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Resource.java
index dd9e05b1155..a07c226a73b 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Resource.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Resource.java
@@ -214,11 +214,12 @@ public abstract class Resource implements Serializable {
public abstract String getQualifier();
/**
- * The parent is used to build the resources tree, for example for relations between classes, packages and projects.
+ * The parent is used to build the resources tree, for example for relations between files, directories and projects.
* <p>
- * Return null if the parent is the project.
+ * Return null if the parent is the current project (or module in case of multi-module).
* </p>
*/
+ @CheckForNull
public abstract Resource getParent();
/**