JavaFx MediaPlayer behaves differently in unit test vs application, why? - java

I want to load meta data from an MP3 file, to be played by a JavaFx MediaPlayer. This works fine in the unit test, but not in the application. In the unit test, 6 items of metaData reported, but zero in the application. The method that "does the work" is the same.
The main class of the application extends Application. The test class extends ApplicationTest from TestFx. Could that affect the behavior?
The application:
public class MediaMain extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
Map<String, Object> meta = metaData();
System.out.printf("Number of meta data: %d.%n", meta.size());
System.out.println(meta);
}
Map<String, Object> metaData() {
File audioFile = new File("src/main/resources", "beingBoiled.mp3");
final URI uri = audioFile.toURI();
final String source = uri.toString();
Media media = new Media(source);
new MediaPlayer(media);
return media.getMetadata();
}
}
The unit test:
class MediaMainTest extends ApplicationTest {
#Test
void testMeta() {
MediaMain main = new MediaMain();
Map<String, Object> metaData = main.metaData();
assertNotEquals(0, metaData.size());
System.out.printf("Number of meta data: %d.%n", metaData.size());
System.out.println(metaData);
}
}
Printout from the application:
Number of meta data: 0.
{}
Printout from the unit test:
Number of meta data: 6.
{year=1980, artist=The Human League, raw metadata={ID3=java.nio.HeapByteBufferR[pos=254 lim=3214 cap=3214]}, album=Travelogue, genre=(52), title=Being Boiled}
What could be the reason? It's a mystery to me. Written with Java 11, JavaFx 11.0.2 and TestFx 4.0.15-alpha.

You are referencing a file with a location of src/main/resources, this is probably not a good idea as your deployed application likely won't have a src/main/resources directory, plus the resource might be bundled within the application jar rather than as a file on disk, so using a file protocol to access it won't work.
It is probably best to use something like below:
String mediaLoc = getClass().getResource("/beingBoiled.mp3").toExternalForm()
Media media = new Media(mediaLoc)
Like in How load css file in javafx8. The exact location of the resource to be loaded may differ based on build and project structure. If you don't want to load from the class path, but instead via a File or over network http call, then you would need to use something else.
The above code assumes that your build system is setup to copy the media from the src/main/resources to your target packaging location and package the resource into the application distributable (e.g. an application jar file) in the root of the jar file.
Make sure that your build system is actually copying the file to the target location. You can check if it is there by running your build, looking at the resultant jar and running jar tvf <myjarfilename>.jar to see if the mp3 resource is in the correct location at the root of the jar file.

Related

FileNotFoundException when running wiremock from jar file

I am running a spring boot application with wiremock. My files structure is like this:
project/main/
- java/package/Wiremock.java
- resources/wiremock/__files/file.json
Inside Wiremock.java I am calling WireMockServer like this:
WireMockServer wiremockServer = new WireMockServer(WireMockConfiguration.wireMockConfig()
.withRootDirectory(getClass().getResource("/wiremock").getPath())
.port(port));
wiremockServer.start();
wiremockServer.stubFor(get(urlEqualTo("/myurl"))
.willReturn(aResponse()
.withBodyFile("file.json")
.withHeader(CONTENT_TYPE, APPLICATION_JSON_VALUE)
.withStatus(HTTP_OK)));
When I am running it locally it works as expected.
When I compile the app to a jar file , a jar file /Users/user/project-0.0.1-SNAPSHOT.jar is generated with the structure:
BOOT-INF/classes/
- wiremock/__files/file.json
- package/Wiremock.class
But when I run the jar file , I'm getting the following error:
java.lang.RuntimeException: java.io.FileNotFoundException: /Users/user/jar:file:/Users/user/project-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/wiremock/__files/file.json (No such file or directory)
Please help, thanks
if this path is correct?
/Users/user/jar:file:/Users/user/project-0.0.1-SNAPSHOT.jar!/BOOT-
INF/classes!/wiremock/__files/file.json (No such file or directory)
I find there is one more "!" after XXXX.jar and classess.
I just meet the same issue today, when i run wire mock in IDEA, it works. but when i run the application by java -jar mode, wired mock server cannot find the json mock file. the root cause of this issue is that when initialization of wire mock server, it will found the json file by com.github.tomakehurst.wiremock.common.ClasspathFileSource
class, it will recursively add files to list of the config path which you specified. the logic of add file is showed below like this.
public List<TextFile> listFilesRecursively() {
if (this.isFileSystem()) {
this.assertExistsAndIsDirectory();
List<File> fileList = Lists.newArrayList();
this.recursivelyAddFilesToList(this.rootDirectory, fileList);
return this.toTextFileList(fileList);
} else {
return FluentIterable.from(toIterable(this.zipFile.entries())).filter(new Predicate<ZipEntry>() {
public boolean apply(ZipEntry jarEntry) {
return !jarEntry.isDirectory() && jarEntry.getName().startsWith(ClasspathFileSource.this.path);
}
}).transform(new Function<ZipEntry, TextFile>() {
public TextFile apply(ZipEntry jarEntry) {
return new TextFile(ClasspathFileSource.this.getUriFor(jarEntry));
}
}).toList();
}
}
it will recursively add file which is absolutely started with the path. but when you run with java -jar, the jarEntry.getName is started with 'BOOT-INF'. one of the solution is that override the method with a subclass extend ClasspathFileSource, and modify the match rule. it will fix

NullPointer with afterburner.fx when trying to create View

Afterburner.fx has broken for me and I can't seem to get it working again.
In my main method I have this:
#Override
public void start(Stage primaryStage) throws Exception{
Map<Object, Object> customProperties = new HashMap<>();
Injector.setConfigurationSource(customProperties::get);
final StackPane views = new StackPane();
customProperties.put("views", views);
BattleView battleView = new BattleView();
Parent view = battleView.getView();
view.setVisible( false );
view.setId("battle");
views.getChildren().add(view);
...
}
Yet I seem to hit an exception when I get to the BattleView battleView = new BattleView(); line. Afterburner fx seems to be trying to evaluate toString() on ui.battle.BattleView and it doesn't like it, see the below picture:
And in the terminal results in:
I haven't found any help from similiar questions so was hoping someone could point me in the right direction! Help!
Edit: Same error after moving battle.css and battle.fxml to resources/ui/battle:
Edit2:
Since you're using Java 11 and module system, your resource output directory have to be in the same output directory as the module they belong to.
Judging by the images in your post, you're using gradle and you build your project directly from IDEA.
You need to tell IDE to copy your resources to the same output directory:
//build.gradle
plugins {
...
id 'idea' //add idea plugin
}
...
//put compiled classes and resources in the same directory (change the path if needed)
idea.module.outputDir file("out/production/classes")
If you plan to build with gradle too:
//put compiled classes and resources in the same directory (change the paths if needed)
sourceSets.main.output.resourcesDir = "build/classes/java/main"
sourceSets.test.output.resourcesDir = "build/classes/java/test"
and you'll probably need to open package with resource files, so that the framework can access them:
//module-info.java
module YourModuleName {
...
opens ui.battle to afterburner.fx; //add this
}
edit:
The 'idea' in 'idea.module.outputDir' is greyed out with the error 'Cannot resolve symbol 'idea''.
It's not really an error, but you can get rid of it easily:
//use this format instead of the previous one
idea {
module.outputDir file("out/production/classes")
}
Im getting an nullPointer error from input streams where I am trying to load resources, such as: setImage(new Image(getClass().getClassLoader().getResourceAsStream("images/ui/mineStartButton.png")));
Do not call getClassLoader() or you'll need to open the package with the image resource - even if the calling code is in the same module (check Javadoc):
//you need to add '/' at the beginning of the path string to make it absolute
getClass().getResourceAsStream("/images/ui/mineStartButton.png")

Read local file in Android Studio JUnit test [duplicate]

In a unit test, how can I read data from a json file on my (desktop) file system, without hardcoding the path?
I would like to read test input (for my parsing methods) from a file instead of creating static Strings.
The file is in the same location as my unit testing code, but I can also place it somewhere else in the project if needed. I am using Android Studio.
Depending on android-gradle-plugin version:
1. version 1.5 and higher:
Just put json file to src/test/resources/test.json and reference it as
classLoader.getResource("test.json").
No gradle modification is needed.
2. version below 1.5: (or if for some reason above solution doesn't work)
Ensure you're using at least Android Gradle Plugin version 1.1. Follow the link to set up Android Studio correctly.
Create test directory. Put unit test classes in java directory and put your resources file in res directory. Android Studio should mark them like follow:
Create gradle task to copy resources into classes directory to make them visible for classloader:
android{
...
}
task copyResDirectoryToClasses(type: Copy){
from "${projectDir}/src/test/res"
into "${buildDir}/intermediates/classes/test/debug/res"
}
assembleDebug.dependsOn(copyResDirectoryToClasses)
Now you can use this method to get File reference for the file resource:
private static File getFileFromPath(Object obj, String fileName) {
ClassLoader classLoader = obj.getClass().getClassLoader();
URL resource = classLoader.getResource(fileName);
return new File(resource.getPath());
}
#Test
public void fileObjectShouldNotBeNull() throws Exception {
File file = getFileFromPath(this, "res/test.json");
assertThat(file, notNullValue());
}
Run unit test by Ctrl+Shift+F10 on whole class or specyfic test method.
For local unit tests (vs. instrumentation tests), you can put files under src/test/resources and read them using classLoader. For example, following code opens myFile.txt file in the resources directory.
InputStream in = this.getClass().getClassLoader().getResourceAsStream("myFile.txt");
It worked with
Android Studio 1.5.1
gradle plugin 1.3.1
In my case, the solution was to add to the gradle file
sourceSets {
test.resources.srcDirs += 'src/unitTests/resources'
}
After it everything was found by AS 2.3.1
javaClass.classLoader.getResourceAsStream("countries.txt")
I though I should add my findings here. I know this is a little old but for the newer versions of Gradle, where there is NO src/test/resources directory, but only one single resources directory for the whole project, you have to add this line to your Gradle file.
android {
testOptions {
unitTests {
includeAndroidResources = true
}
}
}
By doing this you can access your resource with:
this.getClass().getClassLoader().getResourceAsStream(fileName);
I've been searching for this and could not find an answer, so I decided to help others here.
I've had plenty of problems with test resources in Android Studio so I set up a few tests for clarity. In my
mobile (Android Application) project I added the following files:
mobile/src/test/java/test/ResourceTest.java
mobile/src/test/resources/test.txt
mobile/src/test/resources/test/samePackage.txt
The test class (all tests passes):
assertTrue(getClass().getResource("test.txt") == null);
assertTrue(getClass().getResource("/test.txt").getPath().endsWith("test.txt"));
assertTrue(getClass().getResource("samePackage.txt").getPath().endsWith("test/samePackage.txt"));
assertTrue(getClass().getResource("/test/samePackage.txt").getPath().endsWith("test/samePackage.txt"));
assertTrue(getClass().getClassLoader().getResource("test.txt").getPath().endsWith("test.txt"));
assertTrue(getClass().getClassLoader().getResource("test/samePackage.txt").getPath().endsWith("test/samePackage.txt"));
In the same root project I have a Java (not Android) project called data. If I add the same files to the data project:
data/src/test/java/test/ResourceTest.java
data/src/test/resources/test.txt
data/src/test/resources/test/samePackage.txt
Then all the tests above will fail if I execute them from Android Studio, but they pass on the command line with ./gradlew data:test.
To get around it I use this hack (in Groovy)
def resource(String path) {
getClass().getResource(path) ?:
// Hack to load test resources when executing tests from Android Studio
new File(getClass().getClassLoader().getResource('.').path
.replace('/build/classes/test/', "/build/resources/test$path"))
}
Usage: resource('/test.txt')
Android Studio 2.3, Gradle 3.3
If you go to Run -> Edit configurations -> JUnit and then select the run configuration for your unit tests, there is a 'Working directory' setting. That should point to wherever your json file is. Keep in mind this might break other tests.
Actually, this is what worked for me with Instrumentation Tests (Running Android Studio version 3.5.3, Android Gradle Plugin version 3.5.3, Gradle version 6.0.1):
Put your files in src/androidTest/assets folder
In your test file:
InputStream is = InstrumentationRegistry.getInstrumentation().getContext().getAssets().open("filename.txt");
In my case I only needed to create resources folder into test folder and put my resource file in that folder.
Then, in the test simply load the file as resource stream with:
val inputStream =
this.javaClass.classLoader?.getResourceAsStream("gallery.xml")
Reference on medium: https://medium.com/mobile-app-development-publication/android-reading-a-text-file-during-test-2815671e8b3b
Step(1) open Android Studio select Project view
Step(2) and create resources directory under test.
Please look at attached screenshot for Step(2) result
Step(3) put json file into resources folder(app/src/test/resources)
Please look at attached screenshot for Step(3) result
Step(4) Create a common class to handle reading local json files and converting to respective models using Gson
Example :-
object TestHelper {
private val gson = Gson()
fun loadJsonAsString(fileName: String): String {
val inputStream = javaClass.getResourceAsStream("/$fileName")
return getStringFromInputStream(inputStream)
}
#Throws(IOException::class)
private fun getStringFromInputStream(stream: InputStream?): String {
var n = 0
val buffer = CharArray(1024 * 4)
val reader = InputStreamReader(stream, "UTF8")
val writer = StringWriter()
while (-1 != reader.read(buffer).also { n = it }) writer.write(buffer, 0, n)
return writer.toString()
}
fun <T> convertJsonToModel(jsonString: String, classT: Class<T>): T{
return gson.fromJson(jsonString, classT)
}
}
Step(5) load the json file stored locally in resources directory created in Step(2)
val GET_USER_INFORMATION_RESPONSE_FILE_NAME = "user_response.json"
val jsonString = loadJsonAsString(GET_USER_INFORMATION_RESPONSE_FILE_NAME)
val networkStatusResponse =
convertJsonToModel(jsonString, UserResponse::class.java)
Step(6) at the end of Step(5) you would have converted local json file into required model class that can be used to write your unit tests.

Arquillian: path relative to project instead of server

How can I use a project-relative path when using Arquillian/Shrinkwrap to test my testcases?
IDataSet dataSet = new FlatXmlDataSetBuilder().build(new File("src\\ZZZZZ.xml"));
insertFromXML(dataSet);
Will give me this exception when testing
java.io.FileNotFoundException: C:\Uprogs\jboss-eap-6.2.4\bin\src\ZZZZZ.xml
It tries to locate the file within the folders of the server on which I deploy the test onto.
Rather than that, I want him to look in the folders relative to my project (e.g. C:\Users\xy\workspaces\MyProject\src\ZZZZZ.xml). Searched the internet but found nothing
Shrinkwrap gets deployed like this:
#Deployment
public static Archive<?> createDeployment() {
File[] libs = Maven.resolver()
.loadPomFromFile("pom.xml").resolve(
"jcifs:jcifs"
, "org.dbunit:dbunit"
, "com.ibm:db2jcc_license_cisuz"
, "com.ibm:db2jcc"
)
.withTransitivity()
.asFile();
return ShrinkWrap.create(WebArchive.class, "test.war")
.addAsLibraries(libs)
.addPackage("de.abc.RuleEditor")
.addAsResource("de/abc/RuleEditor/messages.properties", "messages.properties")
.addAsManifestResource("test-jboss-deployment-structure.xml","jboss-deployment-structure.xml")
.addAsWebInfResource("test-beans.xml", "beans.xml")
.addAsWebInfResource(
new StringAsset("<faces-config version=\"2.0\"/>"), "faces-config.xml")
.merge(ShrinkWrap.create(GenericArchive.class).as(ExplodedImporter.class)
.importDirectory("src/main/webapp").as(GenericArchive.class), "/", Filters.include(".*\\.xhtml$"));
}
How can I use a project-relative path when using Arquillian/Shrinkwrap (...)?
It's a ridiculous approach, don't go that way :]
The idea behind Arquillian is to create micro-deployments (it means: jar/war/ear archive using ShrinkWrap tool) and include everything inside that archive.
So please modify your deployment:
#Deployment
public static Archive<?> createDeployment() {
return ShrinkWrap.create(WebArchive.class, "test.war")
(...)
.addAsLibraries(libs)
// Add in below way any additional file to the archive
.addAsResource("path-to-testset.xml", "dbunit/testset.xml")
.addPackage("de.abc.RuleEditor")
.addAsResource("de/abc/RuleEditor/messages.properties", "messages.properties")
.addAsManifestResource("test-jboss-deployment-structure.xml","jboss-deployment-structure.xml")
(...)
}
And then use getResourceAsStream() to load file from the class path:
#Test
public void test_something() {
FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder();
builder.setColumnSensing(true);
FlatXmlDataSet xmlDataSet = builder.build(
this.getClass().getResourceAsStream("/dbunit/testset.xml"));
// ...
It is much better, as everything what is needed to test, is already included inside archive. No relative, nor absolute path names.
My personal advice is: be careful about DbUnit, as perhaps you notice in the future, crafting and managing many xml data sets may become bigger and bigger problem as your project will grow. That is why I prefer DbSetup.

java resource images not displaying

I have been trying to get image resources to display on a GUI I am developing, but am having a difficult time getting them to display. I've come across other questions about loading resources such as java-swing-displaying-images-from-within-a-jar and images-will-not-work-in-a-jar-file, but they aren't working for me.
My issue appears to be the same as the first link, where images appear when run from Eclipse and don't appear when run from the command line using Jars. However the solution to those questions don't make the images appear.
The code I have for retrieving resources is:
public class R {
public static final String resourcePackage = "path/to/image/package";
/**
* Returns the resource string that refers to the <code>resource</code> file
* in the <code>path.to.image.package.png</code> package.
*
* #param resource
* the file in the <code>png</code> package
* #return the full resource string
*/
public static String png(String resource) {
return String.format("%s/png/%s", resourcePackage, resource);
}
public static ResizableIcon resizableIcon(String resource) {
return ImageWrapperResizableIcon.getIcon(R.class.getClassLoader()
.getResourceAsStream(resource), new Dimension(48, 48));
}
}
I call it when generating the GUI
JCommandButton connect = new JCommandButton(i18ln.getString("ports"),
R.resizableIcon(R.png("serial-port-32x32.png")));
A print statement indicates that the resource was found because R.class.getClassLoader().getResourceAsStream returns an instance of sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream.
I'm stumped. I have spent hours trying to figure this out, but could use some help. Any ideas?
FYI: I don't think it matters, but I am using Flamingo for my GUI.
EDIT: per Stefan's request
src/
main/
java/
com.company.project (packages)
R.java
MyGui.java
resources/
com.company.project (packages)
.png (package)
serial-port-32x32.png
(more images)
.i18ln (package)
MyGui.properties
As for more code, I don't know what else I can provide that will be of much benefit for this question. All the code for retrieving resources and how I use that code is provided above. Was there something specific you were looking for?
UPDATE:
When I create a Jar using Eclipse and run it from the command line, the image resources display properly. When I create a Jar using Gradle, the images are not displayed. So there is something being done differently when generating the Jars that allows images resources to be accessed properly via the Eclipse Jar, but not the Gradle Jar. I opened a question on the Gradle forums with respect to this issue.
Dependent on the environment in which your application is (Standalone, ApplicationServer), you will need to use the appropriate ClassLoader.
If you can have a utility class, Utils, you can try something like this:
/* Returns a instance of InputStream for the resource */
public static InputStream getResourceAsStream(String resource)
throws FileNotFoundException {
String stripped = resource.startsWith("/")?resource.substring(1):resource;
InputStream stream = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader != null) {
stream = classLoader.getResourceAsStream(stripped);
}
if (stream == null) {
stream = Utils.class.getResourceAsStream(resource);
}
if (stream == null) {
stream = Utils.class.getClassLoader().getResourceAsStream(stripped);
}
if (stream == null) {
throw new FileNotFoundException("Resource not found: " + resource);
}
return stream;
}
For use:
Utils.getResourceAsStream("com/company/project/png/serial-port-32x32.png");
Here try this example HOW TO LOAD IMAGES TO YOUR ECLIPSE PROJECT. Hopefully this will explain things for you, More STEPS HERE
Don't use ClassLoader, thingy though, as described in this Java Doc , A quote from it states "All class loaders will search for a resource first as a system resource, in a manner analogous to searcing for class files."
Forget about the class loader, check the path. If feasible use getResource i.o. getResourceAsStream (question of style: more direct, and delivers null when not found).
As getResource(AsStream) is class based, the paths are relative, so try this:
R.class.getResource("/" + resource)
Create a resources package and place this class and your images in it:
public final class Resources {
public static ImageIcon getImage(String filename) {
URL resourceUrl = Resources.class.getResource(filename);
return new ImageIcon(resourceUrl);
}
}
Edit:
I have rebuild your structure with maven and flamingo (using your R class) and it works with these additions:
Change:
R.class.getClassLoader().getResourceAsStream(resource);
to:
R.class.getResource("png/"+resource);
I have used the maven-assemble-plugin to build the jar as described here.
URL imageurl = getClass().getResource("/images/serial-port-32x32.png");//relative path of the image as argument
Image myPicture = Toolkit.getDefaultToolkit().getImage(imageurl);
Use this Image 'myPicture' as the first argument of ImageWrapperResizableIcon.getIcon method

Categories

Resources