I'm creating a Mojo which doesn't need a project to run.
I would like to use something similar to org.apache.maven.model.FileSet (providing multiple directories with includes and excludes) as a #parameter but my problem is that I need to be able to set those values using command line.
Any idea how to achieve this?
See:
Guide to Developing Java Plugins, Parameter Types With Multiple Values
Using Plugin Tools Java5 Annotations
Maven Plugin Tool for Annotations, Supported Annotations
org.apache.maven.model.FileSet
POM
<groupId>so</groupId>
<artifactId>multiple-values-maven-plugin</artifactId>
<version>1.0</version>
<packaging>maven-plugin</packaging>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.3.3</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.4</version>
<scope>provided</scope><!-- annotations are needed only to build the plugin -->
</dependency>
</dependencies>
<!-- This latest plugin has to be used if using Java 8 classes. -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.4</version>
</plugin>
</plugins>
</build>
Mojo
package so;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.maven.model.FileSet;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
#Mojo( name = "values", requiresProject = false )
public class MultipleValuesMojo extends AbstractMojo
{
#Parameter( property = "array", required = true )
private String[] array;
#Parameter( property = "list", required = true )
private List<String> list;
#Parameter( property = "set", required = true )
private String[] setElements;
private Set<String> set;
#Parameter( property = "map", required = true )
private String[] mapEntries;
private Map<String, String> map;
#Parameter( property = "includes", required = true )
private List<String> includes;
#Parameter( property = "excludes", required = true )
private List<String> excludes;
#Override
public void execute() throws MojoExecutionException
{
getLog().info( "Array: " + Arrays.toString( array ) );
getLog().info( " List: " + list.toString() );
set = Arrays.stream( setElements ).collect( Collectors.toSet() ); // with Java >=8
addSetElementsToSet(); // with Java <8
getLog().info( " Set: " + set.toString() );
map = Arrays.stream( mapEntries ).collect( Collectors.toMap( s -> s, s -> s ) ); // with Java >=8
putMapEntriesToMap(); // with Java <8
getLog().info( " Map: " + map.toString() );
getLog().info( "Includes: " + includes.toString() );
getLog().info( "Excludes: " + excludes.toString() );
FileSet fileSet = new FileSet();
fileSet.setIncludes( includes );
fileSet.setExcludes( excludes );
getLog().info( " FileSet: " + fileSet.toString() );
} // execute()
private void addSetElementsToSet()
{
set = new HashSet<String>( setElements.length );
for ( String entry : setElements )
{
set.add( entry );
}
} // addSetElementsToSet()
private void putMapEntriesToMap()
{
map = new HashMap<String, String>( mapEntries.length );
for ( String entry : mapEntries )
{
int equalsPosition = entry.indexOf( "=" );
map.put(
entry.substring( 0, equalsPosition ),
entry.substring( equalsPosition + 1 ) );
}
} // putMapEntriesToMap()
} // MultipleValuesMojo
Run
mvn so:multiple-value-maven-plugin:values
-Darray=VALUE_1,VALUE_2,VALUE_3
-Dlist=VALUE_1,VALUE_2,VALUE_3
-Dset=VALUE_1,VALUE_2,VALUE_3
-Dmap=KEY_1=VALUE_1,KEY_2=VALUE_2,KEY_3=VALUE_3
-Dincludes=/,/usr/*
-Dexcludes=/root,/tmp
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building multiple-values-maven-plugin 1.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- multiple-values-maven-plugin:1.0:values (default-cli) # multiple-values-maven-plugin ---
[INFO] Array: [VALUE_1, VALUE_2, VALUE_3]
[INFO] List: [VALUE_1, VALUE_2, VALUE_3]
[INFO] Set: [VALUE_3, VALUE_2, VALUE_1]
[INFO] Map: {KEY_1=VALUE_1, KEY_3=VALUE_3, KEY_2=VALUE_2}
[INFO] Includes: [/, /usr/*]
[INFO] Excludes: [/root, /tmp]
[INFO] FileSet: FileSet {directory: null, PatternSet [includes: {/, /usr/*}, excludes: {/root, /tmp}]}
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.671 s
[INFO] Finished at: 2015-07-25T21:44:09+02:00
[INFO] Final Memory: 11M/115M
[INFO] ------------------------------------------------------------------------
Anyone looking for the solution:
-D<some-property>.fileSet=['path-to-fileset']
did the trick for me. It might require slight modification, depending on a plugin you're configuring, but you get the idea.
Tested on Maven 3.5.0
Related
I had used S4SDK VDM on my Integration Testing to test my ODATA services. There were some issues during the implementation & Alexander bestowed me to get it working. (VDM for Integration Tests)
When I had executed the JUnit in eclipse it works well. However when the JUnit runs during the Maven Build/ in the pipeline, it fails with the below error
[INFO]
[INFO] Results:
[INFO]
[ERROR] Errors:
[ERROR] BusinessServiceIT.createBusinessService:132->createLandscapeObject:214 » ErpOData
[INFO]
[ERROR] Tests run: 21, Failures: 0, Errors: 1, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 09:34 min
[INFO] Finished at: 2019-06-13T16:00:26+02:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:3.0.0-M3:test (default-test) on project x-srv-landscapeManagement-integration-tests: There are test failures.
[ERROR]
[ERROR] Please refer to C:\Users\xxxxx\git\x-service-landscapeManagement\srv\integration-tests\target\surefire-reports for the individual test results.
[ERROR] Please refer to dump files (if any exist) [date].dump, [date]-jvmRun[N].dump and [date].dumpstream.
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
[ERROR]
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR] mvn <goals> -rf :x-srv-landscapeManagement-integration-tests
public static void beforeClass() {
mockUtil.mockDefaults();
mockUtil.mockAuditLog();
lsoCreateHelper.withCustomHttpHeader("Authorization", jwToken).onRequestAndImplicitRequests();
connectionHelper.withCustomHttpHeader("Authorization", jwToken).onRequestAndImplicitRequests();
}```
``` #Before
public void beforeEach() throws URISyntaxException, IOException, ODataException {
mockUtil.mockDestination("localhorst", new URI("http://localhost:" + randomServerPort));
erpConfCtx = new ErpConfigContext("localhorst");
final String publicKey = FileUtils.readFile("publicKey.txt");
final Map<String, String> verificationkey = ImmutableMap.of("verificationkey", publicKey);
final JsonObject xsuaaServiceCredentials = new Gson().toJsonTree(verificationkey).getAsJsonObject();
when(((ScpCfCloudPlatform) CloudPlatformAccessor.getCloudPlatform())
.getXsuaaServiceCredentials(org.mockito.ArgumentMatchers.any(DecodedJWT.class)))
.thenReturn(xsuaaServiceCredentials);
}```
private UUID createLandscapeObject(String lsoType, String name, String customerNumber, String source,
String usecase, String tenantId, String tenantType) throws ODataException {
Properties properties = new Properties();
List<Properties> propertySet = new ArrayList<>();
if (usecase != null) {
properties.setName("useCase");
properties.setValue(usecase);
properties.setSource(source);
propertySet.add(properties);
}
if (tenantId != null) {
propertySet = new ArrayList<>();
properties.setName("TenantId");
properties.setValue(tenantId);
properties.setSource(source);
propertySet.add(properties);
}
if (tenantType != null) {
propertySet = new ArrayList<>();
properties.setName("TenantType");
properties.setValue(tenantType);
properties.setSource(source);
propertySet.add(properties);
}
LandscapeObjects landscapeObjects = new LandscapeObjects(null, null, null, null, null, name, "benufromit_test",
lsoType, customerNumber, source, null, null, propertySet);
LOG.info("benu-business1");
final LandscapeObjectsCreateFluentHelper lsoCreateHelper = lmsService.createLandscapeObjects(landscapeObjects)
.withCustomHttpHeader("Authorization", jwToken).onRequestAndImplicitRequests();
landscapeObjects = lsoCreateHelper.execute(erpConfCtx);
return landscapeObjects.getId();
}```
[ERROR] Errors:
[ERROR] BusinessServiceIT.createBusinessService:132->createLandscapeObject:214 » ErpOData
target\surefire-reports
-------------------------------------------------------------------------------
Test set: com.sap.crun.landscape.BusinessServiceIT
-------------------------------------------------------------------------------
Tests run: 3, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 66.107 s <<< FAILURE! - in com.sap.crun.landscape.BusinessServiceIT
createBusinessService(com.sap.crun.landscape.BusinessServiceIT) Time elapsed: 2.463 s <<< ERROR!
com.sap.cloud.sdk.s4hana.datamodel.odata.helper.ODataVdmErrorResultHandler$ErpODataException:
The endpoint responded with HTTP error code 500.
. .
Full error message:
<?xml version='1.0' encoding='UTF-8'?><error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><code/><message xml:lang="en">Service not available: LandscapeService.</message></error>
at com.sap.crun.landscape.BusinessServiceIT.createLandscapeObject(BusinessServiceIT.java:214)
at com.sap.crun.landscape.BusinessServiceIT.createBusinessService(BusinessServiceIT.java:132)```
**TestApplication**
package com.sap.crun.landscape;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan(basePackages = {"com.sap.cloud.servicesdk.spring", "com.sap.crun.landscape"})
#ServletComponentScan( "com.sap.cloud.sdk" )
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
I have a rest endpoint as below:
#PostMapping(value = "/customers/{customerId}")
public SomeResponse manageCustomers(#PathVariable String customerId){
...
}
This endpoint picks customer data from one system for the given customerId and saves it in another system. Thus, it doesn't require any request body.
I need to write an integration test for this. When I use testRestTemplate for this, I can't find a good enough method where I can pass requestEntity as null. Whenever I do that, I get an exception saying 'uriTemplate must not be null'.
I have tried to use 'postForObject', 'exchange' methods but doesn't work. Any ideas?
Below is my IT:
#SpringBootTest(webEnvironmentSpringBootTest.WebEnvironment.RANDOM_PORT)
#DirtiesContext
#ActiveProfiles("test")
class CustomerIT extends Specification{
#LocalServerPort
private int port;
#Autowired
private TestRestTemplate restTemplate
def "should get customer from first system and save in second system"() {
given:
def customerUrl = new URI("http://localhost:" + port + "/customers/1234")
def expected = new SomeObject(1)
when:
def someObject =
restTemplate.postForEntity(customerUrl, null, SomeObject.class)
then:
someObject != null
someObject == expected
}
}
Using postForEntity(url, null, ResponseType.class) works for me.
My postmapping is equal to your except for the responseType. I used Map just as an example
#PostMapping(value = "/customers/{customerId}")
public Map<String, String> manageCustomers(#PathVariable String customerId){
return new HashMap<String, String>(){{ put("customerId", customerId); }};
}
Test to verify that it works
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class CustomerControllerTest {
#LocalServerPort
private int port;
private final TestRestTemplate testRestTemplate = new TestRestTemplate();
#Test
public void postEmptyBodyShouldReturn200OK() {
String customerId = "123";
ResponseEntity responseEntity = testRestTemplate
.postForEntity(format("http://localhost:%s/ping/customers/%s", port, customerId), null, Map.class);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(responseEntity.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON_UTF8);
assertThat(responseEntity.getBody()).isNotNull();
assertThat(((LinkedHashMap) responseEntity.getBody()).size()).isEqualTo(1);
assertThat(((LinkedHashMap) responseEntity.getBody()).get("customerId")).isEqualTo(customerId);
}
}
Running this test in maven
$ mvn -Dtest=CustomerControllerTest test
(...removed unnecessary output...)
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.137 s - in com.ins.example.demo.rest.CustomerControllerTest
10:04:54.683 [Thread-3] INFO o.s.s.c.ThreadPoolTaskExecutor - Shutting down ExecutorService 'applicationTaskExecutor'
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.940 s
[INFO] Finished at: 2019-04-07T10:04:55+02:00
[INFO] ------------------------------------------------------------------------
I'm writing a Maven 3 plugin that needs to know the transitive dependencies of a given org.apache.maven.model.Dependency. How can I do that?
In Maven 3, you access all dependencies in a tree-based form by relying on the maven-dependency-tree shared component:
A tree-based API for resolution of Maven project dependencies.
This component introduces the DependencyGraphBuilder that can build the dependency tree for a given Maven project. You can also filter artifacts with a ArtifactFilter, that has a couple of built-in implementations to filter by groupId, artifactId (IncludesArtifactFilter and ExcludesArtifactFilter), scope (ScopeArtifactFilter), etc. If the fiter is null, all dependencies are kept.
In your case, since you target a specific artifact, you could add a IncludesArtifactFilter with the pattern groupId:artifactId of your artifact. A sample code would be:
#Mojo(name = "foo")
public class MyMojo extends AbstractMojo {
#Parameter(defaultValue = "${project}", readonly = true, required = true)
private MavenProject project;
#Parameter(defaultValue = "${session}", readonly = true, required = true)
private MavenSession session;
#Component(hint = "default")
private DependencyGraphBuilder dependencyGraphBuilder;
public void execute() throws MojoExecutionException, MojoFailureException {
ArtifactFilter artifactFilter = new IncludesArtifactFilter(Arrays.asList("groupId:artifactId"));
ProjectBuildingRequest buildingRequest = new DefaultProjectBuildingRequest(session.getProjectBuildingRequest());
buildingRequest.setProject(project);
try {
DependencyNode rootNode = dependencyGraphBuilder.buildDependencyGraph(buildingRequest, artifactFilter);
CollectingDependencyNodeVisitor visitor = new CollectingDependencyNodeVisitor();
rootNode.accept(visitor);
for (DependencyNode node : visitor.getNodes()) {
System.out.println(node.toNodeString());
}
} catch (DependencyGraphBuilderException e) {
throw new MojoExecutionException("Couldn't build dependency graph", e);
}
}
}
This gives access to the root node of the dependency tree, which is the current project. From that node, you can access all chidren by calling the getChildren() method. So if you want to list all dependencies, you can traverse that graph recursively. This component does provide a facility for doing that with the CollectingDependencyNodeVisitor. It will collect all dependencies into a List to easily loop through it.
For the Maven plugin, the following dependency is therefore necessary:
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-dependency-tree</artifactId>
<version>3.0</version>
</dependency>
So the following code should give you an impression how to do it.
#Mojo( name = "test", requiresDependencyResolution = ResolutionScope.COMPILE, defaultPhase = LifecyclePhase.PACKAGE ...)
public class TestMojo
extends AbstractMojo
{
#Parameter( defaultValue = "${project}", readonly = true )
private MavenProject project;
public void execute()
throws MojoExecutionException, MojoFailureException
{
List<Dependency> dependencies = project.getDependencies();
for ( Dependency dependency : dependencies )
{
getLog().info( "Dependency: " + getId(dependency) );
}
Set<Artifact> artifacts = project.getArtifacts();
for ( Artifact artifact : artifacts )
{
getLog().info( "Artifact: " + artifact.getId() );
}
}
private String getId(Dependency dep) {
StringBuilder sb = new StringBuilder();
sb.append( dep.getGroupId() );
sb.append( ':' );
sb.append( dep.getArtifactId() );
sb.append( ':' );
sb.append( dep.getVersion() );
return sb.toString();
}
}
The above code will give you the resolved artifacts as well as dependencies. You need to make a difference between the dependencies (in this case the project dependencies without transitive and the artifacts which are the solved artifacts incl. transitive.).
Most important is requiresDependencyResolution = ResolutionScope.COMPILE otherwise you will get null for getArtifacts().
The suggestion by Tunaki will work for any kind of artifact which is not part of your project...The question is what you really need?
Updated Exec Summary of Solution
Following up from the answer provided by Victor, I implemented a Java class that lists the contents of a folder resource in the classpath. Most critical for me was that this had to work when the class path resource is discovered when executing from the IDE, from an exploded uberjar, or from within an unexploded uberjar (which I typically create with the maven shade plugin.) Class and associated unit test available here.
Original Question
I am seeing strange behavior with the maven-shade-plugin and class path resources when I run very simple
java Test program that access a directory structure in a standard maven project like this:
src/main
Test.java
resources/
resource-directory
spark
junk1
zeppelin
junk2
When run from the IDE or the exploded maven shaded .jar (please see below)
it works correctly, which means it prints this:.
result of directory contents as classpath resource:[spark, zeppelin]
The source is as follows:
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
public class Tester {
public void test(String resourceName) throws IOException {
InputStream in = this.getClass().getClassLoader().getResourceAsStream(resourceName);
System.out.println("input stream: " + in);
Object result = IOUtils.readLines(in);
System.out.println("result of directory contents as classpath resource:" + result);
}
public static void main(String[] args) throws IOException {
new Tester().test("resource-directory");
}
}
Now, if I run mvn clean install in my project and run the
maven shaded .jar under ${project.dir}target, I see the following exception:
> java -jar target/sample.jar
Exception in thread "main" java.lang.NullPointerException
at java.io.FilterInputStream.read(FilterInputStream.java:133)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at org.apache.commons.io.IOUtils.readLines(IOUtils.java:1030)
at org.apache.commons.io.IOUtils.readLines(IOUtils.java:987)
at org.apache.commons.io.IOUtils.readLines(IOUtils.java:968)
at Tester.test(Tester.java:16)
at Tester.main(Tester.java:24)
Running with Exploded .jar
> mkdir explode/
> cd explode/
> jar xvf ../sample.jar
......
inflated: META-INF/MANIFEST.MF
created: META-INF/
etc etc.
> ls # look at contents of exploded .jar:
logback.xml META-INF org resource-directory Tester.class
#
# now run class with CLASSPATH="."
(master) /tmp/maven-shade-non-working-example/target/explode > java Tester
input stream: java.io.ByteArrayInputStream#70dea4e
result of directory contents as classpath resource:[spark, zeppelin] # <<<- works !
I have the whole project here: https://github.com/buildlackey/maven-shade-non-working-example
but for convenience, here is the pom.xml(below), with two maven shade configs that I tried.
Note: I don't think the IncludeResourceTransformer would be of any use because my resources are appearing
at the appropriate levels in the .jar file.
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.foo.core</groupId>
<artifactId>sample</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>sample</name>
<url>http://maven.apache.org</url>
<properties>
<jdk.version>1.8</jdk.version>
<junit.version>4.11</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency><!-- commons-io: Easy conversion from stream to string list, etc.-->
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
</dependencies>
<build>
<finalName>sample</finalName>
<plugins>
<!-- Set a compiler level -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
</configuration>
</plugin>
<!-- Maven Shade Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<!-- Run shade goal on package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<!-- add Main-Class to manifest file -->
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>Tester</mainClass>
</transformer>
<!-- tried with the stanza below enabled, and also disabled: in both cases, got exceptions from runs -->
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>src/main/resources/</resource>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
anyway, thanks in advance for any help you can provide ~
chris
UPDATE
This didn't work for me in Spring when I tried it (but I'd be interested if anyone has success with a Spring approach). I have a working alternative which I will post shortly. But if you care to comment on how to fix this broken Spring attempt, I'd be very interested.
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import java.io.IOException;
public class Tester {
public void test(String resourceName) throws IOException {
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resourceResolver.getResources("resource-directory/*");
for (Resource resource : resources) {
System.out.println("resource: " + resource.getDescription());
}
}
public static void main(String[] args) throws IOException {
new Tester().test("resource-directory/*");
}
}
The problem is that getResourceAsStream can read only files as a stream, not folders, from a jar file.
To read folder contents from a jar file you might need to use the approach, like described in the accepted answer to this question:
How can I get a resource "Folder" from inside my jar File?
To supplement the answer from my good friend Victor, here is a full code solution. below. The full project is available here
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* List entries of a subfolder of an entry in the class path, which may consist of file system folders and .jars.
*/
public class ClassPathResourceFolderLister {
private static final Logger LOGGER = LoggerFactory.getLogger(ClassPathResourceFolderLister.class);
/**
* For each entry in the classpath, verify that (a) "folder" exists, and (b) "folder" has child content, and if
* these conditions hold, return the child entries (be they files, or folders). If neither (a) nor (b) are true for
* a particular class path entry, move on to the next entry and try again.
*
* #param folder the folder to match within the class path entry
*
* #return the subfolder items of the first matching class path entry, with a no duplicates guarantee
*/
public static Collection<String> getFolderListing(final String folder) {
final String classPath = System.getProperty("java.class.path", ".");
final String[] classPathElements = classPath.split(System.getProperty("path.separator"));
List<String> classPathElementsList = new ArrayList<String> ( Arrays.asList(classPathElements));
return getFolderListingForFirstMatchInClassPath(folder, classPathElementsList);
}
private static Collection<String>
getFolderListingForFirstMatchInClassPath(final String folder, List<String> classPathElementsList) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("getFolderListing for " + folder + " with classpath elements " + classPathElementsList);
}
Collection<String> retval = new HashSet<String>();
String cleanedFolder = stripTrailingAndLeadingSlashes(folder);
for (final String element : classPathElementsList) {
System.out.println("class path element:" + element);
retval = getFolderListing(element, cleanedFolder);
if (retval.size() > 0) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("found matching folder in class path list. returning: " + retval);
}
return retval;
}
}
return retval;
}
private static String stripTrailingAndLeadingSlashes(final String folder) {
String stripped = folder;
if (stripped.equals("/")) { // handle degenerate case:
return "";
} else { // handle cases for strings starting or ending with "/", confident that we have at least two characters
if (stripped.endsWith("/")) {
stripped = stripped.substring(0, stripped.length()-1);
}
if (stripped.startsWith("/")) {
stripped = stripped.substring(1, stripped.length());
}
if (stripped.startsWith("/") || stripped.endsWith("/")) {
throw new IllegalArgumentException("too many consecutive slashes in folder specification: " + stripped);
}
}
return stripped;
}
private static Collection<String> getFolderListing( final String element, final String folderName) {
final File file = new File(element);
if (file.isDirectory()) {
return getFolderContentsListingFromSubfolder(file, folderName);
} else {
return getResourcesFromJarFile(file, folderName);
}
}
private static Collection<String> getResourcesFromJarFile(final File file, final String folderName) {
final String leadingPathOfZipEntry = folderName + "/";
final HashSet<String> retval = new HashSet<String>();
ZipFile zf = null;
try {
zf = new ZipFile(file);
final Enumeration e = zf.entries();
while (e.hasMoreElements()) {
final ZipEntry ze = (ZipEntry) e.nextElement();
final String fileName = ze.getName();
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("zip entry fileName:" + fileName);
}
if (fileName.startsWith(leadingPathOfZipEntry)) {
final String justLeafPartOfEntry = fileName.replaceFirst(leadingPathOfZipEntry,"");
final String initSegmentOfPath = justLeafPartOfEntry.replaceFirst("/.*", "");
if (initSegmentOfPath.length() > 0) {
LOGGER.trace(initSegmentOfPath);
retval.add(initSegmentOfPath);
}
}
}
} catch (Exception e) {
throw new RuntimeException("getResourcesFromJarFile failed. file=" + file + " folder=" + folderName, e);
} finally {
if (zf != null) {
try {
zf.close();
} catch (IOException e) {
LOGGER.error("getResourcesFromJarFile close failed. file=" + file + " folder=" + folderName, e);
}
}
}
return retval;
}
private static Collection<String> getFolderContentsListingFromSubfolder(final File directory, String folderName) {
final HashSet<String> retval = new HashSet<String>();
try {
final String fullPath = directory.getCanonicalPath() + "/" + folderName;
final File subFolder = new File(fullPath);
System.out.println("fullPath:" + fullPath);
if (subFolder.isDirectory()) {
final File[] fileList = subFolder.listFiles();
for (final File file : fileList) {
retval .add(file.getName());
}
}
} catch (final IOException e) {
throw new Error(e);
}
return retval;
}
}
I have simple presenter. Announce the call to the class of singleton
private RandomString randomString = RandomString.getInstance();
When assembling maven I have error
[INFO] [ERROR] Error injecting by.gwttest.client.client.application.packet.PacketPagePresenter$MyProxy: Unable to create or inherit binding: No #Inject or default constructor found for by.gwttest.client.client.application.packet.PacketPagePresenter$MyProxy
[INFO] Path to required node:
[INFO]
[INFO] by.gwttest.client.client.application.packet.PacketPagePresenter$MyProxy [com.gwtplatform.mvp.client.gin.AbstractPresenterModule.bindPresenter(AbstractPresenterModule.java:121)]
[INFO]
[INFO] [ERROR] Error injecting by.gwttest.client.client.application.packet.PacketPageView$Binder: Unable to create or inherit binding: No #Inject or default constructor found for by.gwttest.client.client.application.packet.PacketPageView$Binder
[INFO] Path to required node:
[INFO]
[INFO] by.gwttest.client.client.application.packet.PacketPageView [com.gwtplatform.mvp.client.gin.AbstractPresenterModule.bindPresenter(AbstractPresenterModule.java:120)]
[INFO] -> by.gwttest.client.client.application.packet.PacketPageView$Binder [#Inject constructor of by.gwttest.client.client.application.packet.PacketPageView]
[INFO]
[INFO] [ERROR] Errors in 'gen/com/gwtplatform/mvp/client/DesktopGinjectorProvider.java'
[INFO] [ERROR] Line 8: Failed to resolve 'com.gwtplatform.mvp.client.DesktopGinjector' via deferred binding
RandomString
...
private RandomString() {
}
private static class RandomStringHolder {
private final static RandomString instance = new RandomString();
}
public static RandomString getInstance() {
return RandomStringHolder.instance;
}
...
With what it can be connected? Without declaring RandomString project going
Your error is unrelated to the RandomString. The error says that you are missing a #Inject annotated constructor.
Make sure that your PacketPageView and PacketPagePresenter have an empty constructor that is annotated with #Inject.
#Inject
public PacketPagePresenter() {
}
Error was in this code
private String convertMStoTime(long millis) {
//return null;
return String.format(
"%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(millis),
TimeUnit.MILLISECONDS.toMinutes(millis)
- TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS
.toHours(millis)),
TimeUnit.MILLISECONDS.toSeconds(millis)
- TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS
.toMinutes(millis)));
}
TimeUnit dont'realese in GWT