Java GraphQL schema dependency across modules - java

I have a gradle project that is divided into multiple modules. There is a shared module that defines a root GraphQL schema that I want to expose to other modules but I'm not sure how to define this dependency in other modules. Also a requirement is that IntelliJ IDEA would be able to resolve the types in the other modules' GraphQL schema to their definitions in the shared module's schema.
For example, my project has the following structure:
projectRoot
|-- shared/src/main/resources/graphql
| `-- schema.graphql
|-- user/src/main/resources/graphql
| `-- schema.graphql
`-- task/src/main/resources/graphql
`-- schema.graphql
In shared/src/main/resources/graphql/schema.graphql I have defined the following:
type Mutation {}
type Query {}
And in user/src/main/resources/graphql/schema.graphql I have defined the following:
extend type Mutation {}
extend type Query {}
I have defined a dependency on the shared module in the user module's gradle.build file as follows:
dependencies {
api(project(":shared")) // I have tried implementation also
}
I am unable to run the project as I have a few other things to sort out also but IDEA is unable to resolve the types:
The GraphQL I'm using is Spring for GraphQL

In your case, there are two different problems that need to be solved: the Spring for GraphQL auto-detection of schema files, and the IntelliJ IDEA plugin support.
First, if you've structured your application this way, you should tell Spring Boot to look for schema files in the entire classpath with a configuration property:
spring.graphql.schema.locations="classpath*:graphql/**/"
Second, the IntelliJ IDEA plugin for GraphQL support is relying on the .graphqlconfig specification. In your case, you could add a .graphqlconfig file at the root of your project with the following:
{
"projects": {
"shared": {
"includes": ["./shared/src/main/resources/graphql/*.graphql"]
},
"user": {
"includes": ["./user/src/main/resources/graphql/*.graphql"]
},
"task": {
"includes": ["./task/src/main/resources/graphql/*.graphql"]
}
}
}
You can check out the plugin documentation since there are multiple ways to structure your configuration for this use case.

Related

Maven build is picking different Jackson artefacts version on different hosts

I have multi-module projects, which has a multiple Jackson version, though in recently added module POM and Main Project POM it's 2.9.8 (included specifically).
and One of the modules has...
#JsonTypeInfo(
use = Id.NAME
)
#JsonSubTypes({#Type(TermQuery.class), #Type(AllMatchQuery.class)})
#JsonIgnoreProperties({"queryType"})
public abstract class Query implements Serializable {
.....
}
#JsonTypeName("term")
public class TermQuery extends Query {
}
at the time of serialization, I am getting this response(wrong) from a few of the hosts
Case-1
"queryType": "term"
while on the rest of the hosts I am getting result as expected
Case-2
"#type": "term"
At Case-1 expectation is annotated #type (as in case-2) while I am getting query type. Unable to pinpoint the issue, why it is happening?. though it seems Jackson version issue (I am not sure anymore now).
Other Info:-
Apache Maven 3.6.3
[INFO] \- com.xyz:jar:1.0.5-SNAPSHOT:compile (newly added module)
Any thought/way out to diagnose this issue would be appreciated?

Java Bean Validation 2.0 Hibernate Validator - Executable JAR with external XML-Configuration

Context
I'm developing a stand-alone application that reads input-data from a csv-file.
Until now I've used a self-written class to perform input validation,
and the method used for validating a single record from the input file was triggered
immediately after reading a single line. The method was called in the methode for reading the csv-file.
Since the input data will be retrieved by using RESTful Web Services in the future
and we'll forfeit using csv-files, I want to decouple the validation from the csv-reading.
I stumpled upon Bean Validation (JSR 380) and used Hibernate Validator to refactor the validation procedure.
I tried both, adding validation-annotations directly to the Bean class, and using a validation.xml file for configuration.
Both ways work when I run the application from Eclipse.
Problem
The application will be deployed as an executable JAR.
I would like to keep the option to change the validation constraints without the need to repack and redeploy the JAR.
So I'm trying to figure out, if there is a way to exclude the validation.xml (+ further configuration files) from the JAR and put it in some directory "close" to the JAR.
Something like this:
myApp/
|-- JAR
|-- conf/
|-- ValidationMessages.properties
|-- META-INF/
|-- validation.xml
|-- validation/
|-- constraints-myBean.xml
What I tried
Placing the META-INF/-folder in the same directory as the JAR
The JAR runs, but the validation doesn't work.
Referencing the absolute path to constraints-myBean.xml in validation.xml, specifically changing
<constraint-mapping>META-INF/validation/constraints-pbpRecord.xml</constraint-mapping>
to
<constraint-mapping>C:/path/to/myApp/META-INF/validation/constraints-pbpRecord.xml</constraint-mapping>
and including validation.xml in my JAR.
A ValidationException cancels the execution:
Exception in thread "main" javax.validation.ValidationException: HV000096: Unable to open input stream for mapping file C:/Users/wsteffler/Desktop/pbp_import_tool/pbp_orgunit_import/META-INF/validation/constraints-pbpRecord.xml.
at org.hibernate.validator.internal.xml.config.ValidationBootstrapParameters.setMappingStreams(ValidationBootstrapParameters.java:291)
at org.hibernate.validator.internal.xml.config.ValidationBootstrapParameters.<init>(ValidationBootstrapParameters.java:67)
at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.parseValidationXml(AbstractConfigurationImpl.java:595)
at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.buildValidatorFactory(AbstractConfigurationImpl.java:376)
at javax.validation.Validation.buildDefaultValidatorFactory(Validation.java:103)
at de.uniwuppertal.hisinone.orgunitimport.pbp.Main.main(Main.java:220)
Adding the parent-directory of META-INF/ to the classpath (with -classpath argument)
The JAR runs, but the validation doesn't work.
I've read the Bean Validation specification (6.5. Bootstrapping & 9. XML deployment descriptor) and the Hibernate Validator 6.1.0 Reference Guide (8. Configuring via XML), especially looking for solutions in the chapters in parentheses, and searched on StackOverflow and Google for solutions. Unfortunately I haven't found anything that would lead me to a solution so far.
Is it even possible to achieve bootstrapping an external validation.xml when executing a JAR?
If it is, how can I achieve this?
If you'll need more information or parts from my code, I'll update the question with the required information.
Hibernate Validator clearly doesn't support that. For sure the validation.xml needs to be in the jar. We could maybe support having the file: prefix to point to external constraint mappings. I would accept a patch if you were willing to work on that.
Not sure about the resource bundles though so that would be an half baked solution for you.
I wonder if you could just pass a carefully crafted class loader that can load resources from your external location (and delegate everything else to the standard class loader) and use externalClassLoader(ClassLoader) to pass it to HV when configuring the ValidatorFactory.

Shared gradle project in spring boot does not contain yml files

I have projects A and B that both have common project as a compile dependency defined in their build.gradle files like this:
dependencies {
compile project(":common")
compile('org.springframework.boot:spring-boot-starter-actuator')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.boot:spring-boot-starter-cache')
compile("net.oauth.core:oauth:20090617")
compile("net.oauth.core:oauth-httpclient4:20090617")
compile('org.apache.httpcomponents:httpclient')
compile("com.atlassian.jira:jira-rest-java-client:2.0.0-m2")
compile("com.google.guava:guava:18.0")
compile('org.flywaydb:flyway-core')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
This common project has application.yml file with all kind of common information such as database connection properties, hibernate setup, etc. So I do not want to duplicate these files all over the other projects such as A and B.
In project A the main spring boot file looks like this:
#SpringBootApplication(scanBasePackageClasses = {CommonApp.class,
A.class})
public class A {
public static void main(String[] args) {
SpringApplication.run(A.class, args);
}
}
where CommonApp is a main class in the commmon project. This common main file is the following:
#SpringBootApplication
public class CommonApp {
public static void main(String[] args) {
SpringApplication.run(CommonApp.class, args);
}
}
Projects A and B compile just fine, but all yml files that are in the classpath of the common project are not visible from A and B, so I have not choice but to duplicate them manually in A and B
What is the better approach? Can spring boot common projects share resources with other projects?
Notice that ideally solution should not be gradle dependant as I would like to run unit and integration tests from Intellij IDEA which does not use gradle for running tests.
My app structure is
app
|-A
|-build.gradle
|-web
|-B
|-build.gradle
|-common
|-src/main/resources
|-application.yml
|-database.yml
|-web.yml
|-settings.gradle
|-build.gradle
A, B and common are all spring boot apps (common is a boot app too, but it's only used as a dependency for A, B).
If you want a non-gradle solution, you could always add a DAO-esque file to access the required values in the common project then jar your common project and add it as a dependency to projects A and B.
Edit: I apologize, I did not explain very well. When I say "DAO-esque file", what I mean to say is a file of getter (and setters if needed) that access the properties file. For example, have a getter file that is a singleton. On creation, create a static reference to the property file. When Project A (or B) needs a property, it can call to this file to get the property.
As for a gradle solution, it looks like your above is fairly close with your
compile project(":common")
code. Do you have a settings.gradle file that has the line
includeFlat "common"
and a reference to the common project in the same directory as Project A and B? For example
Project A
(...Project A's files...)
Project B
(...Project B's files...)
Common
(...Common's files...)

Spring Boot application with part of JSP files from other Maven module

Let's assume that we have Spring Boot based web application using JSP templates. It can be even as simple as in the following example (from official Spring Projects repository)
Project structure:
|-src/main/java/
| |-sample.tomcat.jsp
| |-SampleTomcatJspApplication.java
| |-WelcomeController.java
|-src/main/resources/
| |-application.properties
|-src/test/java/
| |-...
|-src/main/webapp/
| |-WEB-INF
| |-jsp
| |-welcome.jsp
|-pom.xml
Properties file contains view prefix /WEB-INF/jsp/ and suffix .jsp and when requesting / we see properly rendered content of welcome.jsp.
WelcomeController.java
application.properties
Changes
Now let's make the following changes
Duplicate WelcomeController.java as WelcomeController2.java and change a bit request mapping, model attributes and returned view name, e.g.:
#RequestMapping("/2")
public String welcome2(Map<String, Object> model) {
model.put("message", "Hi from Welcome2");
return "welcome2";
}
Duplicate welcome.jsp as welcome2.jsp so that src/main/webapp will be like this:
|-src/main/java/
| |-sample.tomcat.jsp
| |-SampleTomcatJspApplication.java
| |-WelcomeController.java
| |-WelcomeController2.java
...
|-src/main/webapp/
| |-WEB-INF
| |-jsp
| |-welcome.jsp
| |-welcome2.jsp
Then when requesting /2 we can see properly rendered content of welcome2.jsp.
The question
What is the way of splitting such project into two maven projects, so that both WelcomeController2.java and welcome2.jsp could be moved to other project (maven dependency) and still be successfully resolved when /2 URL is requested?
Note that with Spring Boot web-fragment.xml (that could be placed in META-INF directory of dependency) is ignored.
Unfortunately, I don't know of an easy way to do this but one approach I've used is to create a Maven artifact just like normal for the main project, in your case probably a WAR artifact. This project will need to have a dependency upon your second project. Then your second project would consist of two components:
A standard Maven JAR artifact containing the compiled class files.
A Maven assembly ZIP consisting of the JSP files that need to be included in the WAR archive as well. This will be generated from the second project during the package phase, but will need to be included as a separate dependency on the main project using a zip classifier.
When the first project is built, you'll need to unpack the assembly dependency as part of the packaging process for the WAR archive. If you want this to work in an IDE, you'll probably need to unpack it in a fairly early phase, such as process-resources or generate-sources.

Can maven projects have multiple parents?

We have Java and Flex projects. We currently have 1 base pom that contains the configurations we want to use for both projects. Problem with this is: Flex projects inherit configuration, for example, for javadoc and pmd plugins, which is not desirable.
I want to clean it up and have a real base pom, and then a java-base-pom and a flex-base-pom. But how does this work in a multi-module that has both a Flex part and a Java part?
We have plugins to our own application where we use the following structure:
my-plugin
my-plugin-client (flex)
my-plugin-server (java)
my-plugin just contains a pom.xml with <modules/> section. I would use my-plugin pom.xml as a parent for both, but then I cannot also use the java base-pom or the flex base-pom as parent. What would be the best approach for this?
Even though maven projects have single parent, they can import any number of other pom's like this:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>my-shared-dependencies</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
This has two important differences compared to a parent:
Plugins defined in the imported pom won't be imported
Dependencies defined in the imported pom won't be added to the current pom, it will only import dependencies into the dependency management section
However, if your parent pom has a <dependencies> section and you want to include those into your dependencies, then you can add the parent to your <dependencies> section just like a regular dependency:
<dependency>
<groupId>org.example</groupId>
<artifactId>my-shared-dependencies</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
Even though the same dependency is already imported, the version tag has to be specified again. To reduce duplication, it can be stored in a property
A project can have only one parent (unlike multiple inheritance in C++) but this parent can be part of a bigger parent hierarchy. As pointed out by others, you could thus have something like this:
base-pom/
|-- flex-base-pom
| |-- my-plugin-client
| | `-- pom.xml
| `-- pom.xml
|-- java-base-pom
| |-- my-plugin-server
| | `-- pom.xml
| `-- pom.xml
`-- pom.xml
That said, I noticed you wrote that your actual problem is that:
flex projects inherit configuration for javadoc and pmd for example, which they do not want.
You should use the pluginManagement element to avoid this situation:
pluginManagement is an element that is seen along side plugins. Plugin Management contains plugin elements in much the same way, except that rather than configuring plugin information for this particular project build, it is intended to configure project builds that inherit from this one. However, this only configures plugins that are actually referenced within the plugins element in the children. The children have every right to override pluginManagement definitions.
So, in the parent pom, configure your plugins in pluginManagement (javadoc and pmd for example), and reference them within the plugins element in the desired children (only in my-plugin-server here). This would solve your current issue.
The only way is to have base-pom as parent of java-base-pom and flex-base-pom.
I have similar structure for my spring projects:
base-pom (basic configuration - eclipse, reports, repositories, etc)
|
+ spring-base-pom (spring definitions)
|
+ spring-jar-base-pom (jar specific definitions)
|
+ spring-war-base-pom (spring web and servlet dependencies)
|
+ spring-webapp-base_pom (spring web mvc dependencies)
I've cross this exact proble also, and the best solution I found was to use Inheritance and Aggregation as suggest in this question : does maven support multiple parents (multiple inheritance) ?
You can have an aggregator pom that is not the parent of the projects it
aggregates.
and explain in the Maven Documentation
Inheritance and aggregation create a nice dynamic to control builds through a single, high-level POM (...) Conversely, a POM project may aggregate projects that do not inherit from it.
From this I had my POMs inheritance (pom-master contains communes configurations, and each children the specifics ones) :
pom-master
|-- pom-java
|-- pom-flex
and so my project can get the specifics for each modules configurations as wished :
project (aggregate project-flex & project-java)
|-- project-java
| `-- pom.xml => parent = pom-java
|-- project-flex
| `-- pom.xml ==> parent = pom-flex
`-- pom.xml => parent = pom-master
Hope it will help others as well :)
Just image that pom.xml are in fact Java classes: you can have only one parent (or extends a class), but this parent can also have another parent, and so on.
As I explained here, you must distinguish the parent and aggregation principles in Maven, which means that my-plugin would be considered as an aggregation project, not necessarily a parent project for both my-plugin-client and my-plugin-parent.
So to summarize:
my-plugin will define the base pom for all your projects. Then, you create two new pom projects: java-base-pom and flex-base-pom. They have both my-plugin as parent. Now, my-plugin-client will have java-base-pom as parent, while my-plugin-server will use flex-base-pom for his parent.
This way, my-plugin-client will inherit all properties defined in the my-plugin pom.xml, and also from java-base-pom project.
You can achieve multiple inheritance with profiles:
You create (multiple) profiles in the root pom, and auto activate any variation of these profiles achieves multiple inheritance of maven configuration.

Categories