I am using jqassistant to create a transitive dependency list of artifacts. My aim is to base this on the type dependencies because I want to find architecture deficits by comparing the Maven transitive dependency list with the one given by type dependencies (all artifacts of which at least one type is used in any transitive form).
Unfortunately, the following query only gave back the original artifact basis-vs-bo. The query was applied to a database that I created by scanning a Maven repository.
What did I miss?
MATCH (basis:Artifact{name:"basis-vs-bo",version:"4.0.0"})
WHERE NOT( HAS (basis.classifier))
WITH basis
MATCH (basis) -[:CONTAINS]-> (t:Type) -[:DEPENDS_ON*]-> (s:Type) <-[:CONTAINS]- (a:Artifact)
RETURN DISTINCT a
The Maven repository scanner treats all artifacts in isolation, i.e. dependencies between them are not evaluated while scanning classes.
This is the same behavior as scanning several JAR files from a directory, so dependencies between classes (method invocations, inheritance hierarchies, etc.) are only resolved if the involved classes are located within the same artifact.
As the dependencies between the artifacts are known in the case of the Maven repository it should be possible to apply queries which resolve these dependencies similar to the "classpath:*" concepts but this needs to be evaluated.
Update
The following queries should help getting class based dependencies (DEPENDS_ON) between classes in different artifacts:
Build DEPENDS_ON relations between artifacts based on declared dependencies in POMs:
MATCH
(r:Repository)-[:CONTAINS_POM]->(p1:Pom)-[:DESCRIBES]->(a1:Java:Archive),
(r:Repository)-[:CONTAINS_POM]->(p2:Pom)-[:DESCRIBES]->(a2:Java:Archive),
(p1)-[:DECLARES_DEPENDENCY]->(a2)
MERGE
(a1)-[:DEPENDS_ON]->(a2)
RETURN
a1.fqn, collect(a2.fqn)
Resolve types required by an artifact to those contained in an artifact which is a dependency, a relation RESOLVES_TO is created:
MATCH
(a1:Artifact)-[:DEPENDS_ON]->(a2:Artifact),
(a1)-[:REQUIRES]->(requiredType:Type),
(a2)-[:CONTAINS]->(containedType:Type)
WHERE
requiredType.fqn = containedType.fqn
MERGE
(requiredType)-[:RESOLVES_TO]->(containedType)
RETURN
a1.fqn, a2.fqn, collect(requiredType.fqn)
Propagate DEPENDS_ON relations between types based on the RESOLVES_TO relation:
MATCH
(a1:Artifact)-[:REQUIRES]->(requiredType:Type),
(a1)-[:CONTAINS]->(type:Type)-[:DEPENDS_ON]->(requiredType),
(a2:Artifact)-[:CONTAINS]->(resolvedType:Type),
(requiredType)-[:RESOLVES_TO]->(resolvedType:Type)
MERGE
(type)-[dependsOn:DEPENDS_ON]->(resolvedType)
SET
dependsOn.resolved=true
RETURN
a1.fqn, type.fqn, a2.fqn, collect(resolvedType.fqn)
Does this work for you?
Related
How to add a dependency constraint to a project from a custom gradle plugin?
I want to create a gradle plugin that will constrain transitive dependencies in the project the plugin is applied to. Ideally, I want this plugin to follow the following rules:
Only try and apply a constraint to a project if the it exists in the project. E.g. only apply a constraint on dependency X if dependency X is pulled into the project.
Apply the constraints automatically on application of the plugin, I don't want to create/run an extra task or anything like that.
(Bonus) Don't apply the constraints to primary dependencies, only transitive dependencies.
Here's what I have so far.
class ConstraintPlugin implements Plugin<Project> {
private Map<String, String> constraintMap = [
"jackson-core": "2.13.2",
"logback-classic": "2.3.9"
]
#Override
void apply(Project project) {
project.configurations.each {config ->
config.resolvedConfiguration.resolvedArtifacts.each {dep ->
if (constraintMap.containsKey(dep.name)) {
ModuleVersionIdentifier id = dep.moduleVersion.id
String constraintVersion = constraintMap.get(id.name)
DependencyConstraint dc = new DefaultDependencyConstraint(id.group, id.name, constraintVersion)
config.dependencyConstraints.add(dc)
}
}
}
I'm using a map instantiated within the constraint plugin class with the names of the dependencies I want to constrain along with the versions to constrain to in the project this plugin is applied to. Here I want to constrain the jackson-core and logback-classic dependencies.
My first thought was to run through each configuration and see if that dependency name is present within that configuration. If so, create a new DependencyConstraint and add it to the configuration. However this is not working when I apply the plugin to another project.
Also note I am not disregarding primary dependencies quite yet, this feature is more like a "nice to have" at this point, I haven't figured out how to only look at transitive dependencies within a given configuration.
I think my issue lies with how I am applying the new DependencyConstraint programmatically but I can't seem to find a way to add a constraint that works. The only other way I've tried is project.dependencies.constraints.create(dc) which also doesn't work.
In POM.xml, I am using following properties
<properties>
<spark.version>3.1.1</spark.version>
<jacoco.version>0.7.9</jacoco.version>
<testng.version>6.8.7</testng.version>
<log4j2.version>2.17.1</log4j2.version>
</properties>
Now, If I am not wrong then I can use those keywords as a placeholder anywhere in POM. Also it would automatically override the transitive dependency. We cant use any random name in place of those tags. For example I cant use spk.version in place of spark.version. It has to be very specific if I want to override transitive dependencies. So my question is that where would I find that correct x where in x.version for any dependency?? Say I want to create property for jackson dependency where would I find the exact keyword?
How can I configure my sonarqube analysis to ignore my getters and setters and not count them as duplicated line. Because I have them both on my entites and on my DTO class. So the duplications % is up to 15%.
Thanks in advance.
Unfortunately, sonar do not provide many rules about getter/setter :
You can configure which files will be reviewed by sonarqube. This could be an exclusion by package or by class name.
For instance, you can exclude com.company.business.plip.dto by adding this to your sonar-project.properties :
sonar.exclusions=src/main/java/com/company/business/plip/dto/**
Considering your dto are just empty shells, containing only privated fields and getters/setters ; this wouldn't cause a huge impact to your code coverage.
You can set exclusions specifically for duplications using this:
sonar.cpd.exclusions=src/main/java/com/company/business/plip/dto/**
I'm using Jackson2RepositoriesPopulatorFactoryBean to populate my bdd from json files.
It work perfectly but fail to find repository for object that are child of this repository. ( I have some object inheriting from an abstract one ).
'An exception occurred while running. null: InvocationTargetException:
No repository found for domain type: x.y.z'
I investigate and found that the Populator fetch repository from class name of the object.
My question is : is it possible to change that ? (And set it to fetch parent repo if it fail with actual class repo ?)
EDIT :
A solution could be to add a repository for each class in a package to the list of Repositories in spring context...
How to do that without adding an #RepositoryRestResource interface for each of them ?
Well, it seems I found a solution using the #Document on parent class instead of on child.
This to avoid creating a collection by child.
Plus, I add one repository (#Repository) by child... this is not the best way to do, but this is a solution.
I have two Maven projects, one called project-data and the other one call project-rest which has a dependency on the project-data project.
The Maven build is successful in the project-data project but it fails in the project-rest project, with the exception:
Caused by: org.hibernate.DuplicateMappingException: duplicate import: TemplatePageTag refers to both com.thalasoft.learnintouch.data.jpa.domain.TemplatePageTag and com.thalasoft.learnintouch.data.dao.domain.TemplatePageTag (try using auto-import="false")
I could see some explanation here: http://isolasoftware.it/2011/10/14/hibernate-and-jpa-error-duplicate-import-try-using-auto-importfalse/
What I don't understand, is why this message does not occur when building the project-data project and occurs when building the project-rest project.
I tried to look up in the pom.xml files to see if there was something in there that could explain the issue.
I also looked up the way the tests are configured and run on the project-rest project.
But I haven't yet seen any thing.
The error is basically due to the fact that the sessionFactory bean underlies two entities with the same logical name TemplatePageTag :
One lies under the com.thalasoft.learnintouch.data.jpa.domain package.
The other under the com.thalasoft.learnintouch.data.dao.domain.
Since this fall to an unusual case, you will have Hibernate complaining about the case. Mostly because you may run in eventual issues when running some HQL queries (which are basically entity oriented queries) and may have inconsistent results.
As a solution, you may need either to:
Rename your Entity beans with different name to avoid confusion which I assume is not a suitable solution in your case since it may need much re-factoring and can hurt your project compatibility.
Configure your EJB entities to be resolved with different names. As you are configuring one entity using xml based processing and the other through annotation, the schema is not the same to define the entities names:
For the com.thalasoft.learnintouch.data.jpa.domain.TemplatePageTag entity, you will need to add the name attribute to the #Entity annotation as below:
#Entity(name = "TemplatePageTag_1")
public class TemplatePageTag extends AbstractEntity {
//...
}
For the com.thalasoft.learnintouch.data.dao.domain.TemplatePageTag, as it is mapped using an hbm xml declaration, you will need to add the entity-name attribute to your class element as follows:
<hibernate-mapping>
<class name="com.thalasoft.learnintouch.data.dao.domain.TemplatePageTag"
table="template_page_tag"
entity-name="TemplatePageTag_2"
dynamic-insert="true"
dynamic-update="true">
<!-- other attributes declaration -->
</class>
</hibernate-mapping>
As I took a look deeper into your project strucure, you may need also to fix entity names for other beans as you have been following the same schema for many other classes, such as com.thalasoft.learnintouch.data.jpa.domain.AdminModule and com.thalasoft.learnintouch.data.dao.domain.AdminModule.
This issue could be fixed by using a combination of #Entity and #Table annotations. Below link provides a good explanation and difference between both.
difference between name-attribute-in-entity-and-table