How can I get maven to just print pom coordinates? - maven

I would like maven to parse a pom file for me and just print out the coordinates of the generated artifact(s). Maven is obviously parsing this info, I just want to know how to get it printed and then have maven stop. I want to use this in some shell scripting, and parsing the pom seems onerous to do in bash - especially with all the inheritance implications and dependency coordinates listed throughout. I don't want any building to occur since I may only have the POM, not the source files.
The best way I've found so far is to parse the output of this:
mvn -N dependency:tree
This seems a bit heavy-weight since it parses ALL dependencies. Is there a better way to do this?

You can create a small java programm which exactly does this like the following:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
public class PomRead {
public String getPomVersion(Model model) {
String result = model.getVersion();
if (result == null) {
throw new IllegalArgumentException("The artifact does not define a version.");
}
return result;
}
public Model readModel(InputStream is) throws IOException, XmlPullParserException {
MavenXpp3Reader model = new MavenXpp3Reader();
Model read = model.read(is);
return read;
}
public Model readModel(File file) throws IOException, XmlPullParserException {
FileInputStream fis = new FileInputStream(file);
return readModel(fis);
}
public String getVersionFromPom(File pomFile) throws IOException, XmlPullParserException {
Model model = readModel(pomFile);
return getPomVersion(model);
}
public static void main(String[] args) {
if (args.length != 1) {
System.err.println("Invalid number of arguments.");
System.err.println("");
System.err.println("usage: pom.xml");
return;
}
String pom = args[0];
File pomFile = new File(pom);
if (!pomFile.exists() || !pomFile.isFile() || !pomFile.canRead()) {
System.err.println("File " + pomFile + " can not be accessed or does not exist.");
return;
}
PomRead pomRead = new PomRead();
try {
String version = pomRead.getVersionFromPom(pomFile);
System.out.println(version);
} catch (IllegalArgumentException e) {
System.err.println(e.getMessage());
} catch (IOException e) {
System.err.println(e.getMessage());
} catch (XmlPullParserException e) {
System.err.println(e.getMessage());
}
}
}
You need of course the following pom.xml for that small program where a single dependency is important:
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model</artifactId>
<version>3.0.5</version>
</dependency>
May be it should be added such a goal to one of the numerous maven plugins to support such a thing. The above prints out the version only but can simply be enhanced to print also groupId and artifactId.

Related

How to get maven dependency tree programmatically

want to print maven dependency tree (all the dependencies including transitive dependencies) programmatically by just reading pom.xml file without connecting to remote repository.
Not really possible, sorry. Also, have you checked the answer and comments here? How can you display the Maven dependency tree for the *plugins* in your project?
I can recommend to take a look at the maven resolver project which has some example code which might be sufficient as a starting point:
https://github.com/apache/maven-resolver/tree/master/maven-resolver-demos/maven-resolver-demo-snippets/src/main/java/org/apache/maven/resolver/examples
You can do this by using ProcessBuilder to retrieve the result of maven's dependency:tree command.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public static void main(String[] args) {
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("cmd.exe", "/c", "mvn -f \"C:\\myprojectpath\"", "dependency:tree");
try {
Process process = processBuilder.start();
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
int exitCode = process.waitFor();
System.out.println("\nExited with error code : " + exitCode);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Read more here.

List Files from Templates Directory in Spring Boot

I would like to generate a blog posts overview. For that I want to read the html files from a folder inside the templates folder in the resources folder where Spring Boot stores its templates.
I tried that but it doesnt return an error but also list no files.
What is the way to go here?
Thanks
#Controller
public class Route {
#Autowired
private ResourceLoader resourceLoader;
#RequestMapping("/")
public String home() throws IOException {
final String path = "templates/blog";
final Resource res = resourceLoader.getResource("templates/blog");
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(res.getInputStream()))) {
reader.lines().forEachOrdered(System.out::println);
}
return "blog/a";
}
}
#Controller
public class Route {
#Value("classpath:templates/blog/*")
private Resource[] resources;
#RequestMapping("/")
public String home() throws IOException {
for (final Resource res : resources) {
System.out.println(res.getFilename());
}
return "blog/a";
}
}
did the trick to me.
You should be able to achieve this using NIO2.
In order for NIO2 to work, it requires the concept of FileSystem, and one can be created from the jar URI. Then this file system can be used with Files/Paths.
The code below contains two branches - the first handles loading the files from inside Jar, the second branch - when the code runs from IDE or via "mvn spring-boot:run".
All streams are being used via try-with-resources so they will be auto-closed.
The find function starts from the top of the file system and recursively searches for html files.
public static void readFile(String location) throws URISyntaxException {
URI uri = Objects.requireNonNull(ReadFromJar.class.getClassLoader().getResource(location)).toURI();
if (uri.getScheme().equals("jar")) { //inside jar
try (FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap())) { //build a new FS that represents the jar's contents
Files.find(fs.getPath("/"), 10, (path, fileAttr) -> // control the search depth (e.g. 10)
fileAttr.isRegularFile() //match only files
&& path.toString().contains("blog") //match only files in paths containing "blog"
&& path.getFileName().toString().matches(".*\\.html")) // match only html files
.forEach(ReadFromJar::printFileContent);
} catch (IOException ex) {
ex.printStackTrace();
}
}
else { //from IDE or spring-boot:run
final Path path = Paths.get(uri);
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(path)) {
dirStream.forEach(ReadFromJar::printFileContent);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void printFileContent(final Path file) {
try {
System.out.println("Full path: " + file.toAbsolutePath().toString());
Files.lines(file).forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}

Reading property file in different module

The static method in my class has to read a property file located in another module.
public class Util
{
private static void readProp()
{
Properties prop = new Properties();
String fileName = "/appconfig.properties"; //File in another module
InputStream inputStream = null;
try
{
inputStream = ClassLoader.getSystemResourceAsStream(propFileName);
if (inputStream != null)
{
prop.load(inputStream);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
The Util method is in module1 while the appconfig.properties is in module2.
The absolute paths for the two is
Util.java :
/Users/user1/IdeaProjects/myProject/module1/src/main/java/com/microsoft/e3/cx/service/windows/search/util/Util.java
appconfig.properties:
/Users/user1/IdeaProjects/myProject/module2/appconfig/base/appconfig.properties
The pom of module2 has module1 as a dependency
<dependency>
<groupId>microsoft.module1</groupId>
<artifactId>module1</artifactId>
<version>${project.version}</version>
</dependency>
My inputStream always comes out to be null. I suppose it is because it is unable to locate this file. Any suggestions on how to fix this?
Try,
Util.getClass().getResourceAsStream("appconfig.properties");

Using PlayFramework + Ebean with Gradle

I'm trying to use the Play Gradle Plugin to compile/package a Play 2.3.x app that uses Ebean.
Everything works fine during compilation and packaging, but when I run the app I get the well known error
Entity type class SomeEntity is not an enhanced entity bean.
Subclassing is not longer supported in Ebean
So how can I can make Gradle run the enhancer during compilation?
This is how i have done it. I am using play 2.4 but should be able to work for you.
First add a configuration in your build.gradle as follows -
configurations {
enhance
}
Next add a dependency on ebeanorm agent as shown below:
dependencies {
enhance group: 'org.avaje.ebeanorm', name: 'avaje-ebeanorm-agent', version: '4.5.3'
}
Ensure you have the required play dependencies in your build.gradle as shown below:
dependencies {
play 'org.avaje:avaje-agentloader:2.1.2'
play "org.avaje.ebeanorm:avaje-ebeanorm-agent:4.5.3"
}
Finally add the following to do the enhancement after the compile task has executed:
model {
components {
play {
binaries.all{binary ->
tasks.withType(PlatformScalaCompile) {
doLast {
ant.taskdef(name: 'ebean', classname: 'com.avaje.ebean.enhance.ant.AntEnhanceTask', classpath: project.configurations.enhance.asPath)
ant.ebean(classSource: "${project.buildDir}/playBinary/classes", packages: 'models.package.name', transformArgs: 'debug=1')
}
}
}
}
}
#koolrich, i had tried the solution and when it didn't compile i moved on, only later to find the only problem was the dbmodels/* expected path while my path was different.
Initially what seemed like magic and confusing jargon about enhancements, the following helped me understand what is going on:
https://openjpa.apache.org/builds/1.2.3/apache-openjpa/docs/ref_guide_pc_enhance.html
Essentially, enhancement is adding some more methods and properties to work with persistance.
I was converting Play 2.5.2 (Java) project from sbt to gradle and facing the same problem, then tried with the solution given by #koolrich. but it did not work well. Every thing was fine but it failed to return data for relation object(it was returning null for relational object). Then i compared the enhanced bytecode generated by sbt and gradle, find out delta. Then find out how the play enhance the bytecode. play enhance bytecode in three steps.
It generates getters and setters for fields it they aren't any in place yet and is done by play-enhancements-plugins(play.core.enhancers.PropertiesEnhancer.generateAccessors)
It rewrites classes that directly access fields to use the accessors instead and is done by play-enhancements-plugins(play.core.enhancers.PropertiesEnhancer.rewriteAccess)
If using Ebean, the Ebean enhancer will be applied to the classes configured via application.conf (ebean-enhancement plugins)
Eaxmple:
Employee employee=Employee.find.byId(1);
Company company=employee.company;
After Step 1&2, this will be converted to
Company company=employee.getCompany();
With Employee#getCompany() being something like
#PropertiesEnhancer.GeneratedAccessor
public Company getCompany(){
return this.company;
}
After step 3, the getter will be modified to be something like
#PropertiesEnhancer.GeneratedAccessor
public Company getCompany(){
return _ebean_get_company();
}
protected Company _ebean_get_company() {
this._ebean_intercept.preGetter("company");
return this.company;
}
So converting sbt to gradle, you have to perform this three steps as gradle play plugins does not support this three steps. For step 3, ebean has enhancement class(ant Task) that can be used(solution given by #koolrich), for step 1 & 2, I wrote another enhancement ant Task which add accessor and rewrite access. here is gradle.build file look like.
configurations {
enhance
playEnhance
}
dependencies {
enhance "org.avaje.ebeanorm:avaje-ebeanorm-agent:4.9.1"
playEnhance 'com.typesafe.play:play-enhancer:1.1.0'
}
model {
components {
play {
binaries.all{binary ->
tasks.withType(PlatformScalaCompile) {
doLast {
ant.taskdef(name: "playenhancetask", classname:"com.xxx.gradlehelper.PlayGradleEnhancherTask", classpath:"${project.buildDir}/playBinary/classes/:${project.configurations.playEnhance.asPath}")
ant.playenhancetask(classSource: "${project.buildDir}/playBinary/classes", packages: 'com.xxx.xxx.*', classpath:"${project.configurations.play.asPath}")
ant.taskdef(name: 'ebean', classname: 'com.avaje.ebean.enhance.ant.AntEnhanceTask', classpath: project.configurations.enhance.asPath)
ant.ebean(classSource: "${project.buildDir}/playBinary/classes", packages: 'com.xxx.xxx.xxx.*', transformArgs: 'debug=1')
}
}
}
}
}
}
dependencies {
play 'org.avaje:avaje-agentloader:2.1.2'
play 'org.avaje.ebeanorm:avaje-ebeanorm:6.18.1'
play 'com.typesafe.play:play-ebean_2.11:3.0.0'
play 'com.typesafe.play:play-enhancer:1.1.0'
play "org.avaje.ebeanorm:avaje-ebeanorm-agent:4.9.1"
play group: 'org.apache.ant', name: 'ant', version: '1.8.2'
}
Here is my ant Task PlayGradleEnhancherTask.java
package com.xxx.gradlehelper;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import play.core.enhancers.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class PlayGradleEnhancherTask extends Task {
String classpath;
String classSource;
String transformArgs;
String packages;
public String getClasspath() {
return classpath;
}
public void setClasspath(String classpath) {
this.classpath = classpath;
}
public void setClassSource(String source) {
this.classSource = source;
}
public void setTransformArgs(String transformArgs) {
this.transformArgs = transformArgs;
}
public void setPackages(String packages) {
this.packages = packages;
}
public void execute() {
if (packages == null) {
throw new BuildException("No message set.");
}
log("classSource: " + classSource + ", packages: " + packages + "\n classPath: "+ classpath);
String dir = packages.trim().replace('.', '/');
dir = dir.substring(0, dir.length() - 1);
String dirPath = classSource + "/" + dir;
File d = new File(dirPath);
if (!d.exists()) {
throw new RuntimeException("File not found " + dirPath + " currentDir:" + new File(".").getAbsolutePath());
}
Path path = Paths.get(dirPath);
List<File> fileNames = new ArrayList();
List<File> files = getFiles(fileNames, path);
//generate property accessor
generateAccessors(files);
//rewrite access
rewriteAccess(files);
}
private void rewriteAccess(List<File> files) {
for (File file: files) {
try{
PropertiesEnhancer.rewriteAccess(classSource+":"+classpath,file);
}catch (Exception e){
String fileName = file == null ? "null" : file.getName() +", e: "+ e.getMessage();
System.err.println("Could not enhance[rewriteAccess]:"+fileName);
}
}
}
private void generateAccessors(List<File> files) {
for (File file: files) {
try{
PropertiesEnhancer.generateAccessors(classSource+":"+classpath,file);
}catch (Exception e){
e.printStackTrace();
String fileName = file == null ? "null" : file.getName();
System.err.println("Could not enhance[generateAccessors]: "+fileName);
}
}
}
private List<File> getFiles(List<File> files, Path dir) {
try(DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
for (Path path : stream) {
if(path.toFile().isDirectory()) {
getFiles(files, path);
} else {
File file = path.toFile();
if(!file.getName().startsWith("Reverse")&& file.getName().endsWith(".class")) {
files.add(file);
}
}
}
} catch(IOException e) {
e.printStackTrace();
}
return files;
}
}

Launch browser automatically after spring-boot webapp is ready

How do I launch a browser automatically after starting the spring boot application.Is there any listener method callback to check if the webapp has been deployed and is ready to serve the requests,so that when the browser is loaded , the user sees the index page and can start interacting with the webapp?
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
// launch browser on localhost
}
Below code worked for me:
#EventListener({ApplicationReadyEvent.class})
void applicationReadyEvent() {
System.out.println("Application started ... launching browser now");
browse("www.google.com");
}
public static void browse(String url) {
if(Desktop.isDesktopSupported()){
Desktop desktop = Desktop.getDesktop();
try {
desktop.browse(new URI(url));
} catch (IOException | URISyntaxException e) {
e.printStackTrace();
}
}else{
Runtime runtime = Runtime.getRuntime();
try {
runtime.exec("rundll32 url.dll,FileProtocolHandler " + url);
} catch (IOException e) {
e.printStackTrace();
}
}
}
#SpringBootApplication
#ComponentScan(basePackageClasses = com.io.controller.HelloController.class)
public class HectorApplication {
public static void main(String[] args) throws IOException {
SpringApplication.run(HectorApplication.class, args);
openHomePage();
}
private static void openHomePage() throws IOException {
Runtime rt = Runtime.getRuntime();
rt.exec("rundll32 url.dll,FileProtocolHandler " + "http://localhost:8080");
}
}
You could do it by some java code. I am not sure if spring boot has something out of the box.
import java.awt.Desktop;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
public class Browser {
public static void main(String[] args) {
String url = "http://www.google.com";
if(Desktop.isDesktopSupported()){
Desktop desktop = Desktop.getDesktop();
try {
desktop.browse(new URI(url));
} catch (IOException | URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
Runtime runtime = Runtime.getRuntime();
try {
runtime.exec("xdg-open " + url);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
I've recently been attempting to get this working myself, I know it's been a while since this question was asked but my working (and very basic/simple) solution is shown below. This is a starting point for anyone wanting to get this working, refactor as required in your app!
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.awt.*;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
openHomePage();
}
private static void openHomePage() {
try {
URI homepage = new URI("http://localhost:8080/");
Desktop.getDesktop().browse(homepage);
} catch (URISyntaxException | IOException e) {
e.printStackTrace();
}
}
}
If you package the application as a WAR file, configure an application server, like Tomcat, and restart the configured application server through your IDE, IDEs can automatically open a browser-tab.
If you want to package your application as a JAR file, your IDE will not be able to open a web browser, so you have to open a web browser and type the desired link(localhost:8080). But in the developing phase, taking these boring steps might be very tedious.
It is possible to open a browser with Java programming language after the spring-boot application gets ready. You can use the third-party library like Selenium or use the following code snippet.
The code snippet to open a browser
#EventListener({ApplicationReadyEvent.class})
private void applicationReadyEvent()
{
if (Desktop.isDesktopSupported())
{
Desktop desktop = Desktop.getDesktop();
try
{
desktop.browse(new URI(url));
} catch (IOException | URISyntaxException e)
{
e.printStackTrace();
}
} else
{
Runtime runtime = Runtime.getRuntime();
String[] command;
String operatingSystemName = System.getProperty("os.name").toLowerCase();
if (operatingSystemName.indexOf("nix") >= 0 || operatingSystemName.indexOf("nux") >= 0)
{
String[] browsers = {"opera", "google-chrome", "epiphany", "firefox", "mozilla", "konqueror", "netscape", "links", "lynx"};
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < browsers.length; i++)
{
if (i == 0) stringBuffer.append(String.format("%s \"%s\"", browsers[i], url));
else stringBuffer.append(String.format(" || %s \"%s\"", browsers[i], url));
}
command = new String[]{"sh", "-c", stringBuffer.toString()};
} else if (operatingSystemName.indexOf("win") >= 0)
{
command = new String[]{"rundll32 url.dll,FileProtocolHandler " + url};
} else if (operatingSystemName.indexOf("mac") >= 0)
{
command = new String[]{"open " + url};
} else
{
System.out.println("an unknown operating system!!");
return;
}
try
{
if (command.length > 1) runtime.exec(command); // linux
else runtime.exec(command[0]); // windows or mac
} catch (IOException e)
{
e.printStackTrace();
}
}
}
Using Selenium to open a browser
To use the selenium library add the following dependency to your pom.xml file.
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
Then in your main class, add the following code snippet.
#EventListener({ApplicationReadyEvent.class})
private void applicationReadyEvent()
{
String url = "http://localhost:8080";
// pointing to the download driver
System.setProperty("webdriver.chrome.driver", "Downloaded-PATH/chromedriver");
ChromeDriver chromeDriver = new ChromeDriver();
chromeDriver.get(url);
}
Notice: It is possible to use most of the popular browsers like FirefoxDriver, OperaDriver, EdgeDriver, but it is necessary to download browsers' drivers beforehand.
Runtime rt = Runtime.getRuntime();
try {
rt.exec("cmd /c start chrome.exe https://localhost:8080");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
The code above worked for me. Change chrome.exe to the browser of your choice and Url to to your choice.
Note: You must include the scheme - http or https, and the browser you choose must me installed, else your app will run without opening the browser automatically.
Works only for windows though.

Resources