Agent JAR not found or no Agent-Class attribute - java

// Fixed: This was not an Error because of code. It was because of the IDE.
I just tried to make a injection for a game called Minecraft.
But i have one Problem. It's not able to load Agent.
Here is the Exception:Exception in thread "main" com.sun.tools.attach.AgentLoadException: Agent JAR not found or no Agent-Class attribute
at sun.tools.attach.HotSpotVirtualMachine.loadAgent(HotSpotVirtualMachine.java:117)
at com.sun.tools.attach.VirtualMachine.loadAgent(VirtualMachine.java:540)
at pw.razex.injectionclient.Injectable.main(Injectable.java:55)
And my code:
AgentLoader [AgentClass]
public class AgentLoader {
public static void agentmain(String agent, Instrumentation instrumentation) {
try {
Class[] loadedClasses = instrumentation.getAllLoadedClasses();
File agentFile = new File(AgentLoader.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
agentFile.deleteOnExit();
for(int i = 0; i < loadedClasses.length; i++) {
Class loadedClass = loadedClasses[i];
if(loadedClass.getName().equals("net.minecraft.client.Minecraft")) {
LaunchClassLoader launchClassLoader = (LaunchClassLoader) loadedClass.getClassLoader();
launchClassLoader.addURL(AgentLoader.class.getProtectionDomain().getCodeSource().getLocation());
launchClassLoader.loadClass(MainGui.class.getName()).newInstance();
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
Main Class:
public class Injectable {
private static VirtualMachineDescriptor minecraftProcess;
public static void main(String[] args) throws Throwable{
OSUtil.initOS();
if(OSUtil.osType != OSUtil.OSType.WINDOWS) {
System.out.println("[X] Invalid OS [" + OSUtil.osType.name() + "]");
System.exit(-1);
}
File sourceFile = new File(Injectable.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
File tempAttachFile = File.createTempFile("lgt", ".dat");
Files.copy(sourceFile.toPath(), tempAttachFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
System.out.println(new File("attach.dll").exists());
if (System.getProperty("java.library.path") != null) {
System.setProperty("java.library.path", new File("attach.dll").getAbsolutePath() + System.getProperty("path.separator") + System.getProperty("java.library.path"));
} else {
System.setProperty("java.library.path", new File("attach.dll").getAbsolutePath());
}
Field field = ClassLoader.class.getDeclaredField("sys_paths");
field.setAccessible(true);
field.set(null, null);
System.loadLibrary("attach");
if(VirtualMachine.list().size() == 0) {
System.out.println("[X] No injectable process found");
System.exit(-1);
}
List<VirtualMachineDescriptor> virtualMachineDescriptors = VirtualMachine.list();
for(VirtualMachineDescriptor virtualMachineDescriptor : virtualMachineDescriptors) {
if(virtualMachineDescriptor.displayName().startsWith("net.minecraft.client.main.Main")) {
minecraftProcess = virtualMachineDescriptor;
VirtualMachine virtualMachine = VirtualMachine.attach(minecraftProcess);
virtualMachine.loadAgent(tempAttachFile.getAbsolutePath());
System.out.println("[O] Attached to minecraft");
}
}
if(minecraftProcess == null) {
System.out.println("[X] Minecraft is not started yet.");
System.exit(-1);
}
}
}
And my pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
<groupId>InjectionClientMaven</groupId>
<artifactId>InjectionClientMaven</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Built-By>David</Built-By>
<Main-Class>de.david.injectionclient.Injectable</Main-Class>
<Agent-Class>de.david.injectionclient.AgentLoader</Agent-Class>
<Class-Path>tools.jar</Class-Path>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>

Make sure your agent jar has the following for its MANIFEST
Manifest-Version: 1.0
Agent-Class: com.package.AgentLoader.agentNameHere
Permissions: all-permissions

Related

luckperms non-static method getUserManager() cannot be referenced from a static context

I'm trying to get user with uuid but an error pops up and says this:
non-static method getUserManager() cannot be referenced from a static context
I tried to place it in a different method and call that method but didn't worked, whatever I do that error still pops up. It could be because I wrote LuckPerms instead of luckPerms but I don't think so.
And here is the code (I deleted some useless stuff)
I tried searching but couldn't find anything, also I've read API like 5 times and it was useless
// BUNGEECORD
import net.md_5.bungee.api.plugin.Plugin;
// BUNGEECORD
//JAVA
import java.util.EnumSet;
//JAVA
//LuckPerms
import net.luckperms.api.LuckPermsProvider;
import net.luckperms.api.LuckPerms;
//LuckPerms
public void onPrivateMessageReceived(final PrivateMessageReceivedEvent event) {
UUID uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + messages.get(0).getContentDisplay()).getBytes());
net.luckperms.api.model.user.User user = LuckPerms.getUserManager().getUser(uuid); // AND HERE IS THE ERROR
DataMutateResult result = user.data().add(Node.builder("group.admin").build());
};
And here is my pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>area</groupId>
<artifactId>amogus</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>dv8tion</id>
<name>m2-dv8tion</name>
<url>https://m2.dv8tion.net/releases</url>
</repository>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>bintray-dv8fromtheworld-maven</id>
<name>bintray</name>
<url>http://dl.bintray.com/dv8fromtheworld/maven</url>
</repository>
<repository>
<id>bungeecord-repo</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>4.3.0_277</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.0-alpha4</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.0-alpha4</version>
</dependency>
<dependency>
<groupId>net.luckperms</groupId>
<artifactId>api</artifactId>
<version>5.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.12.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.16-R0.5-SNAPSHOT</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.16-R0.5-SNAPSHOT</version>
<type>javadoc</type>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<mainClass>area.amogus</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes>
<exclude></exclude>
</excludes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>resources</directory>
</resource>
</resources>
</build>
</project>
Imagine we have a class:
public class MyClass {
public static void main(String[] args) {
MyClass.doThis();
}
public void doThis(){
System.out.println("do this");
}
}
In this case, you will get exactly the same error as you're getting in your code. It means, we cannot access doThis() method, before an instance of MyClass is created, like
MyClass myClass = new MyClass();
myClass.doThis(); //this is valid since we have an instance to call this method on.
I would assume you have to get an instance of LuckPerms object in some way, before calling a .getUserManager() method on it.
Like this:
LuckPerms luckPerms = new LuckPerms(); //assuming there's a respective constructor
luckPerms.getUserManager();
you cannot use LuckPerms.getUserManager(), because you have not instantiated new Object from LuckPerms. Aslo LuckPerms cannot be instantiated because it is an interface. you should implement the interface first and then instantiate and use it.
your code could be like this:
public void onPrivateMessageReceived(final PrivateMessageReceivedEvent event) {
UUID uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + messages.get(0).getContentDisplay()).getBytes());
LuckPerms luckPerms = new LuckPerms() {
#Override
public #org.checkerframework.checker.nullness.qual.NonNull String getServerName() {
return null;
}
#Override
public #org.checkerframework.checker.nullness.qual.NonNull UserManager getUserManager() {
return null;
}
#Override
public #org.checkerframework.checker.nullness.qual.NonNull GroupManager getGroupManager() {
return null;
}
#Override
public #org.checkerframework.checker.nullness.qual.NonNull TrackManager getTrackManager() {
return null;
}
#Override
public #org.checkerframework.checker.nullness.qual.NonNull <T> PlayerAdapter<T> getPlayerAdapter(#org.checkerframework.checker.nullness.qual.NonNull Class<T> aClass) {
return null;
}
#Override
public #org.checkerframework.checker.nullness.qual.NonNull Platform getPlatform() {
return null;
}
#Override
public #org.checkerframework.checker.nullness.qual.NonNull PluginMetadata getPluginMetadata() {
return null;
}
#Override
public #org.checkerframework.checker.nullness.qual.NonNull EventBus getEventBus() {
return null;
}
#Override
public #org.checkerframework.checker.nullness.qual.NonNull Optional<MessagingService> getMessagingService() {
return Optional.empty();
}
#Override
public #org.checkerframework.checker.nullness.qual.NonNull ActionLogger getActionLogger() {
return null;
}
#Override
public #org.checkerframework.checker.nullness.qual.NonNull ContextManager getContextManager() {
return null;
}
#Override
public #org.checkerframework.checker.nullness.qual.NonNull MetaStackFactory getMetaStackFactory() {
return null;
}
#Override
public #org.checkerframework.checker.nullness.qual.NonNull CompletableFuture<Void> runUpdateTask() {
return null;
}
#Override
public void registerMessengerProvider(#org.checkerframework.checker.nullness.qual.NonNull MessengerProvider messengerProvider) {
}
#Override
public #org.checkerframework.checker.nullness.qual.NonNull NodeBuilderRegistry getNodeBuilderRegistry() {
return null;
}
#Override
public #org.checkerframework.checker.nullness.qual.NonNull QueryOptionsRegistry getQueryOptionsRegistry() {
return null;
}
#Override
public #org.checkerframework.checker.nullness.qual.NonNull NodeMatcherFactory getNodeMatcherFactory() {
return null;
}
};
net.luckperms.api.model.user.User user = luckPerms.getUserManager().getUser(uuid); // AND HERE IS THE ERROR
DataMutateResult result = user.data().add(Node.builder("group.admin").build());
}

Can I have cucumber datatable printed in the console output in Java?

E.g. If this is my feature file:
Scenario: Some dummy scenario
Given that I do something with this datatable:
| print | this |
| and | this |
And something else
The output looks like:
Given that I do something with this datatable:
And something else
I was wondering if it is possible to have an output similar to this:
Given that I do something with this datatable:
| print | this |
| and | this |
And something else
Thank you for your help
Edit: As requested, the details of my setup are exposed bellow.
I am using Java and this is the class responsible for the configuration:
#RunWith(Cucumber.class)
#CucumberOptions(plugin = {"pretty", "html:target/cucumber"},
monochrome = false,
glue = {"my.dummy.package"},
features = {"classpath:dummy.feature"})
public class DummyFT {
#Test
public void test() throws IOException {
}
}
These tests are executed as a separate maven goal. My profile section has:
<profile>
<id>functional-tests</id>
<build>
<plugins>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<testSourceDirectory>test/test-functional/java</testSourceDirectory>
<includes>
<include>**/*FT.java</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
and the failsafe plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>${maven.surefire.junit47}</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
And the cucumber dependencies:
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
Finally, the tests are triggered by running:
mvn failsafe:integration-test -Pfunctional-tests
I noticed that there was no solution to this still and couldn't find one anywhere else. We were able to get this to work using a custom afterStep hook, though we're doing this with cucumber-jvm-groovy so obviously it's a bit different. You should be able to take something like this and convert it to java if you're determined though.
import cucumber.api.PickleStepTestStep
import cucumber.api.TestCase
import cucumber.runner.Scenario
import gherkin.pickles.PickleCell
import gherkin.pickles.PickleRow
import gherkin.pickles.PickleTable
import groovy.util.logging.Log4j
import util.StringHelper
import java.lang.reflect.Field
#Log4j
class CucumberHelper {
static TestCase getTestCase(Scenario scenario) {
Field testCaseField = scenario.getClass().getDeclaredField("testCase")
testCaseField.setAccessible(true)
(TestCase) testCaseField.get(scenario)
}
static PickleStepTestStep getStepObject(TestCase testCase, int stepIndex) {
(PickleStepTestStep) testCase.getTestSteps()[stepIndex]
}
static printDataTables(PickleStepTestStep step, boolean stepPassed) {
if (stepContainsDataTable(step)) {
PickleTable table = getDataTable(step)
printTable(table, stepPassed)
}
}
static private boolean stepContainsDataTable(PickleStepTestStep step) {
step?.step?.arguments?.any { it instanceof PickleTable }
}
static private PickleTable getDataTable(PickleStepTestStep step) {
step.step.arguments.find { it instanceof PickleTable }
}
static private void printTable(PickleTable table, boolean stepPassed) {
List<Integer> widths = []
table.rows.each { PickleRow row ->
row.cells.eachWithIndex { PickleCell cell, int i ->
int max = widths[i] ?: 0
int cellWidth = cell.value.length()
if(cellWidth > max){
widths[i] = cellWidth
}
}
}
table.rows.each { PickleRow row ->
printRow(row, stepPassed, widths)
}
}
static private void printRow(PickleRow row, boolean stepPassed, List<Integer> columnWidths) {
String output = ' | '
row.cells.eachWithIndex { PickleCell cell, int i ->
output += cell.value.padRight(columnWidths[i]) + ' | '
}
println getConsoleColor(stepPassed) + output + StringHelper.ANSI_RESET
}
static private String getConsoleColor(boolean stepPassed) {
stepPassed ? StringHelper.ANSI_GREEN : StringHelper.ANSI_RED
}
static void logBeforeStep(PickleStepTestStep step) {
log.trace "BEFORE STEP:\n\n\t${step.stepText}\n"
}
static void logAfterStep(PickleStepTestStep step) {
log.trace "AFTER STEP:\n\n\t${step.stepText}\n"
}
}
And the hook:
AfterStep() { Scenario scenario ->
try {
TestCase testCase = CucumberHelper.getTestCase(scenario)
PickleStepTestStep step = CucumberHelper.getStepObject(testCase, scenario.stepResults.size() - 1)
CucumberHelper.logAfterStep(step)
CucumberHelper.printDataTables(step, !scenario.isFailed())
} catch (Throwable t) {
// ignore, this hook is only for logging
}
}
(Obviously there's some extra functionality in there for our use cases, but it might help others. The StringHelper just adds unicode characters for coloring the output but you could easily remove that and have it print in standard terminal colors.)

Customizing prefix and namespace location in soap request generated using wsdl file

I am struggling to understand why code-generated soap request on the left is not working, but if I tweak it to what's on the right, then it works?
Now that I know what needs to be done to make it work, how do I fix it ?
I added jaxws-maven-plugin to my java project:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.5</version>
<configuration>
<sourceDestDir>src/main/java</sourceDestDir>
<wsdlDirectory>src/main/resources/wsdl</wsdlDirectory>
<wsdlFiles>
<wsdlFile>Flattened_Integrator7.0.wsdl</wsdlFile>
</wsdlFiles>
<keep>true</keep>
</configuration>
<executions>
<execution>
<goals>
<goal>wsimport</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Notice in the picture above without prefix wsse, it doesn't work.
It has to be that word. And it exists in wsdl file.
Does anyone know how:
I can force namespace prefix for "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" to be wsse
Force code to generate namespaces in soap envelope and not in Security section
So, I had to manually add prefix/namespace to envelope and rename all children's prefixes to wsse.
Here is how I did it:
#Component
public class RequestClient {
private static final String WSSE_PREFIX = "wsse";
private static final String WSSE_NAMESPACE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
private static final String NS2_PREFIX = "ns2";
private static final String NS2_NAMESPACE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
private buildSoaprequest(){
...
SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart().getEnvelope();
soapEnvelope.addNamespaceDeclaration(WSSE_PREFIX, WSSE_NAMESPACE);
soapEnvelope.addNamespaceDeclaration(NS2_PREFIX, NS2_NAMESPACE);
SOAPHeader soapHeader = soapMessage.getSOAPHeader();
removeUndesiredBodyNamespaceEntries(soapHeader.getChildElements());
soapHeader.setPrefix(WSSE_PREFIX);
addDesiredBodyNamespaceEntries(soapHeader.getChildElements());
soapMessage.saveChanges();
...
}
private void addDesiredBodyNamespaceEntries(Iterator childElements) {
while (childElements.hasNext()) {
final Object childElementNode = childElements.next();
if (childElementNode instanceof SOAPElement) {
SOAPElement soapElement = (SOAPElement) childElementNode;
soapElement.setPrefix(WSSE_PREFIX);
addDesiredBodyNamespaceEntries(soapElement.getChildElements());
}
}
}
private void removeUndesiredBodyNamespaceEntries(Iterator childElements) {
while (childElements.hasNext()) {
final Object childElementNode = childElements.next();
if (childElementNode instanceof SOAPElement) {
SOAPElement soapElement = (SOAPElement) childElementNode;
//remove any prefix/namespace entries added by JAX-WS in the body element
//it cannot be null, so it will leave wsse
for (String prefix : getNamespacePrefixList(soapElement.getNamespacePrefixes())) {
if (prefix != null) {
soapElement.removeNamespaceDeclaration(prefix);
}
}
// recursively remove prefix/namespace entries in child elements
removeUndesiredBodyNamespaceEntries(soapElement.getChildElements());
}
}
}
private Set<String> getNamespacePrefixList(Iterator namespacePrefixIter) {
Set<String> namespacePrefixesSet = new HashSet<>();
while (namespacePrefixIter.hasNext()) {
namespacePrefixesSet.add((String) namespacePrefixIter.next());
}
return namespacePrefixesSet;
}

Error loading SQLite file on Tomcat war app

I am trying to use and embedded sqlite.db file on my tomcat app. I am working on NetBeans and deploying it on a local server through Netbean's play button. so far so good. However, I am facing a problem when I build a war file and deploy it on a Raspberry PI tomcat. I attach the error below.
For som reason, the same code that works locally, won't work on this tomcat server installed on Raspberry. Any ideas?
Thank you!
==== CODE ====
ContextService.java
public class ContexService implements ServletContextListener {
/**
*
* #param sce
*/
#Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("== context initialized ==");
SqliteTest.getInstance().start();
SqliteTest.getInstance().stop();
}
/**
*
* #param sce
*/
#Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("== context destroyed ==");
SqliteTest.getInstance().stop();
}
}
SQLiteManager.java
public class SQLiteManager {
private static final Logger logger = LoggerFactory.getLogger(SQLiteManager.class);
private static SQLiteManager instance = null;
private static Connection connection = null;
private static int QUERY_TIMEOUT = 5;
private static String TABLE_PROPERTIES = "Properties";
private static String DB_NAME = "safemo.db";
private static class TABLE_PROPERTIES_COLUMNS {
public static final String TRIP_NUMBER = "tripNumber";
}
private SQLiteManager() {
openDB();
}
public static SQLiteManager getInstance() {
if (instance == null) {
instance = new SQLiteManager();
}
return instance;
}
private void openDB() {
if (connection == null) {
connect();
} else {
try {
if (connection.isClosed()) {
connect();
}
} catch (SQLException ex) {
logger.error("Error openning connection : " + ex.getMessage());
}
}
}
private void connect() {
try {
Class.forName("org.sqlite.JDBC");
connection = DriverManager.getConnection("jdbc:sqlite::resource:" + DB_NAME);
logger.debug("Opened database successfully");
} catch (ClassNotFoundException ex) {
logger.error(ex.getMessage());
} catch (SQLException ex) {
logger.error(ex.getMessage());
}
}
public void closeDB() {
try {
if (connection != null) {
connection.close();
}
logger.debug("Connection closed successfully");
} catch (SQLException ex) {
logger.error("Error closing database : " + ex.getMessage());
}
}
public void incrementTripNumber()
{
try {
Statement statement = connection.createStatement();
statement.setQueryTimeout(QUERY_TIMEOUT); // set timeout to 30 sec.
statement.executeUpdate("UPDATE " + TABLE_PROPERTIES + " SET " + TABLE_PROPERTIES_COLUMNS.TRIP_NUMBER + " = " + TABLE_PROPERTIES_COLUMNS.TRIP_NUMBER + " + 1");
} catch (SQLException ex) {
logger.error("Error getting trip number : " + ex.getMessage());
}
}
public int getTripNumber() {
int tripNumber = -1;
try {
Statement statement = connection.createStatement();
statement.setQueryTimeout(QUERY_TIMEOUT); // set timeout to 30 sec.
ResultSet rs = statement.executeQuery("SELECT " + TABLE_PROPERTIES_COLUMNS.TRIP_NUMBER + " FROM " + TABLE_PROPERTIES);
if (rs.next()) {
tripNumber = rs.getInt(TABLE_PROPERTIES_COLUMNS.TRIP_NUMBER);
}
rs.close();
} catch (SQLException ex) {
logger.error("Error getting trip number : " + ex.getMessage());
} finally {
return tripNumber;
}
}
}
SQLiteTest.java
public class SqliteTest
{
private static SqliteTest instance = null;
private static final Logger logger = LoggerFactory.getLogger(SqliteTest.class);
private SqliteTest()
{
}
public static SqliteTest getInstance()
{
if(instance == null)
{
instance = new SqliteTest();
}
return instance;
}
public void start()
{
SQLiteManager sqliteManager = SQLiteManager.getInstance();
logger.debug("TRIP NUMBER : " + sqliteManager.getTripNumber());
sqliteManager.incrementTripNumber();
logger.debug("TRIP NUMBER INCREASED: " + sqliteManager.getTripNumber());
}
public void stop()
{
SQLiteManager.getInstance().closeDB();
}
}
Pom File
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.app</groupId>
<artifactId>SqliteTest</artifactId>
<version>1.0</version>
<packaging>war</packaging>
<name>SqliteTest</name>
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.7</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.8.11.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${endorsed.dir}</outputDirectory>
<silent>true</silent>
<artifactItems>
<artifactItem>
<groupId>javax</groupId>
<artifactId>javaee-endorsed-api</artifactId>
<version>7.0</version>
<type>jar</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
console output on Netbeans local installation
== context initialized ==
08:40:55.398 [http-nio-8080-exec-18] DEBUG SQLiteManager - Opened database successfully
08:40:55.406 [http-nio-8080-exec-18] DEBUG SqliteTest - TRIP NUMBER : 2
08:40:55.543 [http-nio-8080-exec-18] DEBUG SqliteTest - TRIP NUMBER INCREASED: 3
08:40:55.543 [http-nio-8080-exec-18] DEBUG SQLiteManager - Connection closed successfully
And this is the error I am getting when I build the war file and deploy it on Raspberry through Tomcat manager.
== context initialized ==
Aug 25, 2016 6:05:33 PM org.apache.catalina.core.StandardContext startInternal
SEVERE: Error listenerStart
Aug 25, 2016 6:05:33 PM org.apache.catalina.core.StandardContext startInternal
SEVERE: Context [/SqliteTest-1.0] startup failed due to previous errors
== context destroyed ==
Aug 25, 2016 6:05:33 PM org.apache.catalina.loader.WebappClassLoaderBase clearReferencesJdbc
WARNING: The web application [/SqliteTest-1.0] registered the JDBC driver [org.sqlite.JDBC] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
Aug 25, 2016 6:05:33 PM org.apache.catalina.startup.HostConfig deployWAR
INFO: Deployment of web application archive /var/lib/tomcat8/webapps/SqliteTest-1.0.war has finished in 42,719 ms
java version on Raspberry :
openjdk version "1.8.0_40-internal"
OpenJDK Runtime Environment (build 1.8.0_40-internal-b04)
OpenJDK Zero VM (build 25.40-b08, interpreted mode)
Tomcat version : Apache Tomcat/8.0.14 (Debian)
Tomcat JVM 1.8.0_40-internal-b04

Get Maven artifact version at runtime

I have noticed that in a Maven artifact's JAR, the project.version attribute is included in two files:
META-INF/maven/${groupId}/${artifactId}/pom.properties
META-INF/maven/${groupId}/${artifactId}/pom.xml
Is there a recommended way to read this version at runtime?
You should not need to access Maven-specific files to get the version information of any given library/class.
You can simply use getClass().getPackage().getImplementationVersion() to get the version information that is stored in a .jar-files MANIFEST.MF. Unfortunately Maven does not write the correct information to the manifest as well by default!
Instead one has to modify the <archive> configuration element of the maven-jar-plugin to set addDefaultImplementationEntries and addDefaultSpecificationEntries to true, like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
</archive>
</configuration>
</plugin>
Ideally this configuration should be put into the company pom or another base-pom.
Detailed documentation of the <archive> element can be found in the Maven Archive documentation.
To follow up the answer above, for a .war artifact, I found I had to apply the equivalent configuration to maven-war-plugin, rather than maven-jar-plugin:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.1</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
</archive>
</configuration>
</plugin>
This added the version information to MANIFEST.MF in the project's .jar (included in WEB-INF/lib of the .war)
Here's a method for getting the version from the pom.properties, falling back to getting it from the manifest
public synchronized String getVersion() {
String version = null;
// try to load from maven properties first
try {
Properties p = new Properties();
InputStream is = getClass().getResourceAsStream("/META-INF/maven/com.my.group/my-artefact/pom.properties");
if (is != null) {
p.load(is);
version = p.getProperty("version", "");
}
} catch (Exception e) {
// ignore
}
// fallback to using Java API
if (version == null) {
Package aPackage = getClass().getPackage();
if (aPackage != null) {
version = aPackage.getImplementationVersion();
if (version == null) {
version = aPackage.getSpecificationVersion();
}
}
}
if (version == null) {
// we could not compute the version so use a blank
version = "";
}
return version;
}
I am using maven-assembly-plugin for my maven packaging. The usage of Apache Maven Archiver in Joachim Sauer's answer could also work:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
</archive>
</configuration>
<executions>
<execution .../>
</executions>
</plugin>
Because archiever is one of maven shared components, it could be used by multiple maven building plugins, which could also have conflict if two or more plugins introduced, including archive configuration inside.
If you happen to use Spring Boot you can make use of the BuildProperties class.
Take the following snippet from our OpenAPI configuration class as an example:
#Configuration
#RequiredArgsConstructor // <- lombok
public class OpenApi {
private final BuildProperties buildProperties; // <- you can also autowire it
#Bean
public OpenAPI yourBeautifulAPI() {
return new OpenAPI().info(new Info()
.title(buildProperties.getName())
.description("The description")
.version(buildProperties.getVersion())
.license(new License().name("Your company")));
}
}
I know it's a very late answer but I'd like to share what I did as per this link:
I added the below code to the pom.xml:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>build-info</id>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
And this Advice Controller in order to get the version as model attribute:
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.info.BuildProperties;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;
#ControllerAdvice
public class CommonControllerAdvice
{
#Autowired
BuildProperties buildProperties;
#ModelAttribute("version")
public String getVersion() throws IOException
{
String version = buildProperties.getVersion();
return version;
}
}
I spent some time on the two main approaches here and they didn't work-out for me. I am using Netbeans for the builds, may be there's more going on there. I had some errors and warnings from Maven 3 with some constructs, but I think those were easy to correct. No biggie.
I did find an answer that looks maintainable and simple to implement in this article on DZone:
Stamping Version Number and Build Time in a Properties File with Maven
I already have a resources/config sub-folder, and I named my file: app.properties, to better reflect the kind of stuff we may keep there (like a support URL, etc.).
The only caveat is that Netbeans gives a warning that the IDE needs filtering off. Not sure where/how. It has no effect at this point. Perhaps there's a work around for that if I need to cross that bridge. Best of luck.
To get this running in Eclipse, as well as in a Maven build, you should add the addDefaultImplementationEntries and addDefaultSpecificationEntries pom entries as described in other replies, then use the following code:
public synchronized static final String getVersion() {
// Try to get version number from pom.xml (available in Eclipse)
try {
String className = getClass().getName();
String classfileName = "/" + className.replace('.', '/') + ".class";
URL classfileResource = getClass().getResource(classfileName);
if (classfileResource != null) {
Path absolutePackagePath = Paths.get(classfileResource.toURI())
.getParent();
int packagePathSegments = className.length()
- className.replace(".", "").length();
// Remove package segments from path, plus two more levels
// for "target/classes", which is the standard location for
// classes in Eclipse.
Path path = absolutePackagePath;
for (int i = 0, segmentsToRemove = packagePathSegments + 2;
i < segmentsToRemove; i++) {
path = path.getParent();
}
Path pom = path.resolve("pom.xml");
try (InputStream is = Files.newInputStream(pom)) {
Document doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(is);
doc.getDocumentElement().normalize();
String version = (String) XPathFactory.newInstance()
.newXPath().compile("/project/version")
.evaluate(doc, XPathConstants.STRING);
if (version != null) {
version = version.trim();
if (!version.isEmpty()) {
return version;
}
}
}
}
} catch (Exception e) {
// Ignore
}
// Try to get version number from maven properties in jar's META-INF
try (InputStream is = getClass()
.getResourceAsStream("/META-INF/maven/" + MAVEN_PACKAGE + "/"
+ MAVEN_ARTIFACT + "/pom.properties")) {
if (is != null) {
Properties p = new Properties();
p.load(is);
String version = p.getProperty("version", "").trim();
if (!version.isEmpty()) {
return version;
}
}
} catch (Exception e) {
// Ignore
}
// Fallback to using Java API to get version from MANIFEST.MF
String version = null;
Package pkg = getClass().getPackage();
if (pkg != null) {
version = pkg.getImplementationVersion();
if (version == null) {
version = pkg.getSpecificationVersion();
}
}
version = version == null ? "" : version.trim();
return version.isEmpty() ? "unknown" : version;
}
If your Java build puts target classes somewhere other than "target/classes", then you may need to adjust the value of segmentsToRemove.
On my spring boot application, the solution from the accepted answer worked until I recently updated my jdk to version 12. Tried all the other answers as well and couldn't get that to work.
At that point, I added the below line to the first class of my spring boot application, just after the annotation #SpringBootApplication
#PropertySources({
#PropertySource("/META-INF/maven/com.my.group/my-artefact/pom.properties")
})
Later I use the below to get the value from the properties file in whichever class I want to use its value and appVersion gets the project version to me:
#Value("${version}")
private String appVersion;
Hope that helps someone.
The most graceful solutions I've found is that one from J.Chomel: link
Doesn't require any hacks with properties. To avoid issues with broken link in a future I'll duplicate it here:
YourClass.class.getPackage().getImplementationVersion();
And (if you don't have Manifest file in your jar/war yet, for me Intellij Idea's Maven already included them) you will require also a small change in pom.xml:
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
...
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
...
A simple solution which is Maven compatible and works for any (thus also third party) class:
private static Optional<String> getVersionFromManifest(Class<?> clazz) {
try {
File file = new File(clazz.getProtectionDomain().getCodeSource().getLocation().toURI());
if (file.isFile()) {
JarFile jarFile = new JarFile(file);
Manifest manifest = jarFile.getManifest();
Attributes attributes = manifest.getMainAttributes();
final String version = attributes.getValue("Bundle-Version");
return Optional.of(version);
}
} catch (Exception e) {
// ignore
}
return Optional.empty();
}
Here’s a version without Optional<> that just returns null if not present (for quick debugging/dumping):
private static String getVersionFromManifest(Class<?> clazz) {
try {
File file = new File(clazz.getProtectionDomain().getCodeSource().getLocation().toURI());
if (file.isFile()) {
JarFile jarFile = new JarFile(file);
Manifest manifest = jarFile.getManifest();
Attributes attributes = manifest.getMainAttributes();
return attributes.getValue("Bundle-Version");
}
} catch (Exception e) {
// ignore
}
return null;
}
Tried all the answers above but nothing worked for me:
I did not use Spring
Managed to put Version inside of manifest, but someClass.class.getPackage().getImplementationVersion() returned null
However version was appended to the jar file name so I was able to find a jar file using:
new File(ClassLoader.getSystemResource("").toURI()).getParentFile();
and then extract it from the file name.
Java 8 variant for EJB in war file with maven project. Tested on EAP 7.0.
#Log4j // lombok annotation
#Startup
#Singleton
public class ApplicationLogic {
public static final String DEVELOPMENT_APPLICATION_NAME = "application";
public static final String DEVELOPMENT_GROUP_NAME = "com.group";
private static final String POM_PROPERTIES_LOCATION = "/META-INF/maven/" + DEVELOPMENT_GROUP_NAME + "/" + DEVELOPMENT_APPLICATION_NAME + "/pom.properties";
// In case no pom.properties file was generated or wrong location is configured, no pom.properties loading is done; otherwise VERSION will be assigned later
public static String VERSION = "No pom.properties file present in folder " + POM_PROPERTIES_LOCATION;
private static final String VERSION_ERROR = "Version could not be determinated";
{
Optional.ofNullable(getClass().getResourceAsStream(POM_PROPERTIES_LOCATION)).ifPresent(p -> {
Properties properties = new Properties();
try {
properties.load(p);
VERSION = properties.getProperty("version", VERSION_ERROR);
} catch (Exception e) {
VERSION = VERSION_ERROR;
log.fatal("Unexpected error occured during loading process of pom.properties file in META-INF folder!");
}
});
}
}

Categories