I'm trying to import a proto file from a java file in IntelliJ IDEA.
I have a file called A.proto and a file called B.java. I try to import a class Info from the A.proto file in the B.java file like this:
import A.Info;
However, IntelliJ IDEA doesn't look to support proto files and says my class doesn't exist. I installed both plugins Protobuf Support and Protocol Buffer Editor. But it still doesn't work. Any idea?
Problem
IntelliJ recognizes protocol buffer files, but they are not Java, so the Java Compiler doesn't know what to do with them.
Solution with Maven
You can compile those protocol buffers to Java files, which is the step you are currently missing. The best way I know is to use a Maven plugin to do this.
<plugin>
<groupId>com.github.os72</groupId>
<artifactId>protoc-jar-maven-plugin</artifactId>
<version>3.11.4</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<protocVersion>3.0.0</protocVersion> <!-- 2.4.1, 2.5.0, 2.6.1, 3.0.0 -->
<includeDirectories>
<include>src/main/resources/protobuf</include>
</includeDirectories>
<inputDirectories>
<include>src/main/resources/protobuf/</include>
</inputDirectories>
</configuration>
</execution>
</executions>
</plugin>
And dependency for the Protocol Buffer classes:
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.11.4</version>
</dependency>
With this plugin, Intellij will find the created Java classes, after having initially created the sources. This way, only your Protocol Buffer files need to be in Source Control. You let the plugin take care of the compilation to Java.
After creation of the Java classes, you can use them in the rest of your code. You can even view the generated Java classes in the target/generated-sources folder in your Maven Project.
Here's what the mapping between Protocol Buffers and Java looks like:
DistanceWalked.proto
package example;
message DistanceWalked {
string userId = 1;
double distance = 2;
}
DistanceWalkedOuterClass.DistanceWalked.java (generated)
package example;
public class DistanceWalked {
//properties This class isn't pretty...
}
(Full code example with protocol buffers and Maven plugin can be found here: https://github.com/TomCools/protocol-buffers-example)
Link to plugin source: https://github.com/os72/protoc-jar-maven-plugin
Solution without Maven
Without Maven, you have to download the command-line compiler. Documentation on that can be found here: https://developers.google.com/protocol-buffers/docs/javatutorial#compiling-your-protocol-buffers
The proto file is just the description of the message format. It does not contain code that can be interpreted directly in a java context.
The idea of the proto file is to provide a generic, language agnostic specification of the message format.
Based on the proto file, you can generate the corresponding java code. This code can then be used and imported in your java project.
Have a look here on how to generate code from a proto file: https://developers.google.com/protocol-buffers/docs/javatutorial#compiling-your-protocol-buffers
Incase anyone is still stuck -
I found that specifying the path to Intellij fixes the problem:
Preferences -> Languages and Frameworks -> Protocol Buffer -> Uncheck "Configure automatically"
And then add the path to the file.
It should be good for xolstice or os72!
Related
I have a Java 11 application which I develop using Maven and in the pom.xml I have a version declared.
<groupId>my.group.id</groupId>
<artifactId>artifact</artifactId>
<version>0.1.2.3</version>
I want to get this version at runtime e.g. using getClass().getPackage().getImplementationVersion() as it's described in this question. This works as long as I don't package my application as a modular runtime image using Jlink. Then I only get null returned from above call.
I package my application using:
jlink --output target/artifact-image --module-path target/dependencies --launcher MyApp=my.module.name/my.main.Class --add-modules my.module.name
Jlink has actually a parameter --version but this returns the Jlink version instead setting it for the generated artifact.
So, how can I get the version (of my Maven project) at runtime?
How to define it in the modular application?
How to get it into the modular application?
How to read it in the modular application?
I know I could define it in a resource file and simply read it from there, however I prefer to have it only in the pom.xml (= to have a single source of truth).
In the end I did this using the filtering function of the Maven Resources Plugin.
First, enable filtering in the pom.xml:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
Then add a src/main/resources/my-version.properties file containig:
my.version=${project.version}
So you can use the following code in Java:
Properties myProperties = new Properties();
try {
myProperties.load(getClass().getResourceAsStream("/my-version.properties"));
} catch (IOException e) {
throw new IllegalStateException(e);
}
String theVersion = Objects.requireNonNull((String) myProperties.get("my.version"));
I had a similar problem in my last job. I needed to get the version for modules/jars that are not a direct dependency of the application, as well as the module's version itself. The classpath is assembled from multiple modules when the application starts, the main application module has no knowledge of how many jars are added later.
That's why I came up with a different solution, which may be a little more elegant than having to read XML or properties from jar files.
The idea
use a Java service loader approach to be able to add as many components/artifacts later, which can contribute their own versions at runtime. Create a very lightweight library with just a few lines of code to read, find, filter and sort all of the artifact versions on the classpath.
Create a maven source code generator plugin that generates the service implementation for each of the modules at compile time, package a very simple service in each of the jars.
The solution
Part one of the solution is the artifact-version-service library, which can be found on github and MavenCentral now. It covers the service definition and a few ways to get the artifact versions at runtime.
Part two is the artifact-version-maven-plugin, which can also be found on github and MavenCentral. It is used to have a hassle-free generator implementing the service definition for each of the artifacts.
Examples
Fetching all modules with coordinates
No more reading jar manifests or property files, just a simple method call:
// iterate list of artifact dependencies
for (Artifact artifact : ArtifactVersionCollector.collectArtifacts()) {
// print simple artifact string example
System.out.println("artifact = " + artifact);
}
A sorted set of artifacts is returned. To modify the sorting order, provide a custom comparator:
new ArtifactVersionCollector(Comparator.comparing(Artifact::getVersion)).collect();
This way the list of artifacts is returned sorted by version numbers.
Find a specific artifact
ArtifactVersionCollector.findArtifact("de.westemeyer", "artifact-version-service");
Fetches the version details for a specific artifact.
Find artifacts with matching groupId(s)
Find all artifacts with groupId de.westemeyer (exact match):
ArtifactVersionCollector.findArtifactsByGroupId("de.westemeyer", true);
Find all artifacts where groupId starts with de.westemeyer:
ArtifactVersionCollector.findArtifactsByGroupId("de.westemeyer", false);
Sort result by version number:
new ArtifactVersionCollector(Comparator.comparing(Artifact::getVersion)).artifactsByGroupId("de.", false);
Implement custom actions on list of artifacts
By supplying a lambda, the very first example could be implemented like this:
ArtifactVersionCollector.iterateArtifacts(a -> {
System.out.println(a);
return false;
});
Installation
Add these two tags to all pom.xml files, or maybe to a company master pom somewhere:
<build>
<plugins>
<plugin>
<groupId>de.westemeyer</groupId>
<artifactId>artifact-version-maven-plugin</artifactId>
<version>1.1.1</version>
<executions>
<execution>
<goals>
<goal>generate-service</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>de.westemeyer</groupId>
<artifactId>artifact-version-service</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
Feedback
It would be great if you could give the solution a try. Getting feedback about whether you think the solution fits your needs would be even better. So please don't hesitate to add a new issue on any of the github projects if you have any suggestions, feature requests, problems, whatsoever.
Licence
All of the source code is open source, free to use even for commercial products (MIT licence).
Attempting to modify an existing Java/Tomcat app for deployment on Heroku following their tutorial and running into some issues with AppAssembler not finding the entry class. Running target/bin/webapp (or deploying to Heroku) results in Error: Could not find or load main class org.stopbadware.dsp.Main
Executing java -cp target/classes:target/dependency/* org.stopbadware.dsp.Main runs properly however. Here's the relevant portion of pom.xml:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.1.1</version>
<configuration>
<assembleDirectory>target</assembleDirectory>
<programs>
<program>
<mainClass>org.stopbadware.dsp.Main</mainClass>
<name>webapp</name>
</program>
</programs>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
</plugin>
My guess is mvn package is causing AppAssembler to not use the correct classpath, any suggestions?
Your artifact's packaging must be set to jar, otherwise the main class is not found.
<pom>
...
<packaging>jar</packaging>
...
</pom>
The artifact itself is added at the end of the classpath, so nothing other than a JAR file will have any effect.
Try:
mvn clean package jar:jar appassembler:assemble
Was able to solve this by adding "$BASEDIR"/classes to the CLASSPATH line in the generated script. Since the script gets rewritten on each call of mvn package I wrote a short script that calls mvn package and then adds the needed classpath entry.
Obviously a bit of a hack but after a 8+ hours of attempting a more "proper" solution this will have to do for now. Will certainly entertain any more elegant ways of correcting the classpath suggested here.
I was going through that tutorial some time ago and had very similar issue. I came with a bit different approach which works for me very nicely.
First of all, as it was mentioned before, you need to keep your POM's type as jar (<packaging>jar</packaging>) - thanks to that, appassembler plugin will generate a JAR file from your classes and add it to the classpath. So thanks to that your error will go away.
Please note that this tutorial Tomcat is instantiated from application source directory. In many cases that is enough, but please note that using that approach, you will not be able to utilize Servlet #WebServlet annotations as /WEB-INF/classes in sources is empty and Tomcat will not be able to scan your servlet classes. So HelloServlet servlet from that tutorial will not work, unless you add some additional Tomcat initialization (resource configuration) as described here (BTW, you will find more SO questions talking about that resource configuration).
I did a bit different approach:
I run a org.apache.maven.plugins:maven-war-plugin plugin (exploded goal) during package and use that generated directory as my source directory of application. With that approach my web application directory will have /WEB-INF/classes "populated" with classes. That in turn will allow Tomcat to perform scanning job correctly (i.e. Servlet #WebServlet annotations will work).
I also had to change a source of my application in the launcher class:
public static void main(String[] args) throws Exception {
// Web application is generated in directory name as specified in build/finalName
// in maven pom.xml
String webappDirLocation = "target/embeddedTomcatSample/";
Tomcat tomcat = new Tomcat();
// ... remaining code does not change
Changes to POM which I added - included maven-war-plugin just before appassembler plugin:
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>exploded</goal>
</goals>
</execution>
</executions>
</plugin>
...
Please note that exploded goal is called.
I hope that small change will help you.
One more comment on that tutorial and maven build: note that the tutorial was written to show how simple is to build an application and run it in Heroku. However, that is not the best approach to maven build.
Maven recommendation is that you should adhere to producing one artifact per POM. In your case there are should two artifacts:
Tomcat launcher
Tomcat web application
Both should be build as separate POMs and referenced as modules from your parent POM. If you look at the complexity of that tutorial, it does not make much sense to split that into two modules. But if your applications gets more and more complex (and the launcher gets some additional configurations etc.) it will makes a lot of sense to make that "split". As a matter of fact, there are some "Tomcat launcher" libraries already created so alternatively you could use of one them.
You can set the CLASSPATH_PREFIX environment variable:
export CLASSPATH_PREFIX=target/classes
which will get prepended to the classpath of the generated script.
The first thing is that you are using an old version of appassembler-maven-plugin the current version is 1.3.
What i don't understand why are you defining the
<assembleDirectory>target</assembleDirectory>
folder. There exists a good default value for that. So usually you don't need it. Apart from that you don't need to define an explicit execution which bounds to the package phase, cause the appassembler-maven-plugin is by default bound to the package phase.
Furthermore you can use the useWildcardClassPath configuration option to make your classpath shorter.
<configuration>
<useWildcardClassPath>true</useWildcardClassPath>
<repositoryLayout>flat</repositoryLayout>
...
</configruation>
And that the calling of the generated script shows the error is depending on the thing that the location of the repository where all the dependencies are located in the folder is different than in the generated script defined.
I'm looking to convert a WSDL version 1.1 into a WSDL 2.0 format as part of our maven build process.
I've come across the Woden Converter utility which uses XSL to do this conversion, and would like to use it. However, there seems to be no documentation or examples (that I can find) on how to configure or use the related maven plugin: woden-converter-maven-plugin
Does anyone have experience with this, and could they please share the maven plugin config details?
Justification (for those that require it):
We have a contract-first Web Service and have a recent requirement to expose our WSDL in 2.0 format to one particular client. To save on maintaining two identical WSDLs, we'd like to maintain the 1.1 wsdl and have the build process auto-generate the 2.0 version.
Here are the sources for the plugin. There's not much you can set. Check the fields. You can set those up in the <configuration/> section of your plugin.
Consider this:
<plugin>
<groupId>org.apache.woden</groupId>
<artifactId>woden-converter-maven-plugin</artifactId>
<version>1.0M9</version>
<executions>
<execution>
<id>convert</id>
<goals>
<goal>convert</goal>
</goals>
<configuration>
<wsdl><!-- File or URL of wsdl1.1 document.Also multiple
WSDL files can be specified as a comma separated
list. -->
</wsdl>
<targetNS>
<!-- New target namespace for WSDL2.0 document. -->
</targetNS>
<targetDir>
<!-- Target directory for output, default
location is project build directory. -->
</targetDir>
<sourceDir><!-- Source directory for output. --></sourceDir>
<verbose><!-- Verbose mode --></verbose>
<overwrite><!-- Overwrite existing files. --></overwrite>
</configuration>
</execution>
</executions>
</plugin>
I have a problem with a service I am trying to write. I am trying to create a service that runs in the background on a windows system but uses java. I have seen several ways of doing this, but decided on one method that seemed to meet my requirements. The service will check a database for items it needs to work on. When it finds an item in the DB that it needs to do it will run some system commands to take care of them.
I found a way to use the tomcat7.exe file to run a jar as a service and that worked pretty well for basic stuff. Anything I write and compile into my jar file "myService.jar" we'll can call it goes well enough. The problem is that we already have several classes written for accessing the DB and running commands that are precompiled in a library of classes called BGLib-1.0.jar.
I have used this library in writing several jenkins plugins and had no problems calling functions from it. They all work fine when I create an hpi file and deploy it in Jenkins. There the compiler (Eclipse using Maven) packages the BGLib jar in with the plugin jar and Jenkins figures out how to get them to see one another.
When I build my service jar, however, it doesn't work when I deploy it.
I run a command like this to install the Tomcat exe renames to myservice.exe:
d:\myService\bin>myService.exe //IS//myService --Install=D:\myService\bin\myService.exe --Description="run some commands
Java Service" --Jvm=auto --Classpath=D:\myService\jar\myService.jar;D:\myService\jar\BGLib-1.0.jar --StartMode=jvm --
StartClass=com.myCompany.myService.myService --StartMethod=windowsService --StartParams=start --StopMode=jvm --StopClass
=com.myCompany.myService.myService --StopMethod=windowsService --StopParams=stop --LogPath=D:\myService\logs --StdOutpu
t=auto --StdError=auto
When I deploy this with code solely within the myService.jar the service behaves as expected, but when I try to call functions within the BGLib-1.0.jar I get nothing. The jvm appears to crash or become unresponsive. Debugging is a little tricky but it looks like I am getting class not found errors.
I tried adding the entry below in the POM file to see if changing the classpath entry in the manifest would help, but it didn't change the manifest. I am still kind of clueless ass to how the manifest file works. Any documentation on that would be cool. I have been to Maven's site and it doesn't seem to have comprehensive documentation on the tags available. Is there something I need to change in the manifest to get my jar to see external classes? Or is there something I can add that will get Maven to compile the classes from that jar in with my jar?
thanks in advance.
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.myCompany.myService.myService</mainClass>
<customClasspathLayout>BGLib-1.0.jar</customClasspathLayout>
</manifest>
</archive>
</configuration>
To answer mainly the question of the title, you can the shade plugin to include dependencies into your final jar. You can even even relocate the class files (e.g. change package name) within the final jar so that the included classes don't conflict with different versions of the shaded dependency on the classpath. Not sure if this is the best solution for your particular problem though.
You can use the maven-dependency-plugin unpack-dependencies goal to include the contents of a dependency in the resulting artifact.
An example of how to do this would be:
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>${project.artifactId}-fetch-deps</id>
<phase>generate-sources</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
<stripVersion>true</stripVersion>
<excludeTransitive>true</excludeTransitive>
<includeArtifactIds>protobuf-java</includeArtifactIds>
</configuration>
</execution>
</executions>
</plugin>
This will expand the protobuf-java dependency (flatten it) and include the contents in the resulting artifact generated by your build.
Looks to me you actually want to use the appassembler-maven-plugin, otherwise I'd go for the maven-shade-plugin.
How would you structure Freemarker (or an alternative) as a templating code generator into a Maven project? I'm pretty new to Maven and would appreciate some help.
I want to generate some code from templates in my project. [a]
Rather than write my own, googling found freemarker which appears to be used by Spring which is a good enough reference for me, though as I haven't started with it yet, any other suggestions that work well with Maven would be appreciated too.
This website tells me how to add it as a dependency to my pom.xml.
This SO question tells me where the generated sources should go. What I can't work out is how to tie it all together, so I get my generated sources generated from the templates, and then my generated sources used like regular sources for compile, test, jar, javadoc etc. Has anyone else used a template code generator for java within maven and could help?
[a] I know Generics would be the usual solution, and in fact I'm using them, but I have to use templates to cope with the primitive cases, without introducing copy/paste errors. Please trust me on this :-)
I had written a maven plugin for this purpose. It uses the FreeMarker Pre Processor.
Heres the fragment from pom.xml highlighting its usage:
<plugins>
<plugin>
<configuration>
<cfgFile>src/test/resources/freemarker/config.fmpp</cfgFile>
<outputDirectory>target/test/generated-sources/fmpp/</outputDirectory>
<templateDirectory>src/test/resources/fmpp/</templateDirectory>
</configuration>
<groupId>com.googlecode.fmpp-maven-plugin</groupId>
<artifactId>fmpp-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
Here the cfgFile is the path where you keep the config file for FMPP. (if you are not using any special data passing in FreeMarker then an empty file will be enough)
templateDirectory is where you keep the FreeMarker templates.
outputDirectory is where you want the output files to be generated.
I am in process of writing a detailed documentation highlighting the plugins usage and will update the project website accordingly.
Here is another plugin for the job:
https://code.google.com/p/maven-replacer-plugin/
From the original description of the problem it sounds like you should consider creating a Maven Archetype (aka Project Template):
http://maven.apache.org/archetype/maven-archetype-plugin/
And it sounds like you might want to add some properties into the equation:
http://maven.apache.org/archetype/maven-archetype-plugin/examples/create-with-property-file.html
Maven Archetype functionality also provides a means of doing substitution using Apache Velocity (near enough the same as Freemarker) ... but I haven't worked that bit out yet.