Home > Eclipse development, Software Development, Testing > Help! I Programmatically Created a Resource in my Project, but My Code Doesn’t Find It!

Help! I Programmatically Created a Resource in my Project, but My Code Doesn’t Find It!


Let’s say that you wanted to test the existence of a file you programmatically created in your project. While there are a lot of situations where you might create an IResource on the fly, creating a file for use in a test is not a bad example.

The test code could look like this (TestUtilities is a convenience class that does things for me):

...
import org.junit.Assert;
...
    @Test
    public void testFileExistsTrue() throws IOException, CoreException {
        _project = TestUtilities.createProject("x"); //$NON-NLS-1$
        TestUtilities.createTemplateFileInProjectAt(_project, CustomSchemaSupport.SCHEMA_FOLDER_NAME, CustomSchemaSupport.FILENAME);

        boolean actual = _customSchemaSupport.fileExists(_project);

        try {
            Assert.assertTrue(actual);
        } finally {
            // always do this before returning
            _project.delete(true, null);
        }
    }


TestUtilities.createTemplateFileInProjectAt() does the following (I have added additional comments):

    public static void createTemplateFileInProjectAt(IProject project, String relativePath, String filename) throws IOException {
        // Get the path where the file should be created from a properties file.
        String templateFilePath = NewWizardMessages.WizardSchemaNewFileCreationPage_Schema_Template_Location;
        InputStream inputStream = null;
        // Read a template file contained in my plugin
        inputStream = Activator.getDefault().getBundle().getEntry(templateFilePath).openStream();

        // Wrap the above inputStream in a BufferedReader for better performance
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        
        // Create the output file
        File tempFile = new File(getAbsolutePathToProject(project) + File.separator + relativePath + File.separator + CustomSchemaSupport.FILENAME);
        FileWriter fileWriter = new FileWriter(tempFile);
        
        // Write the template file to the output file
        String line = null;
        while((line = bufferedReader.readLine()) != null) {
            fileWriter.write(line);
        }
        fileWriter.close();
    }

The test code method testFileExistsTrue() fails even though the file exists. I know because I debugged this for over an hour.

Since I am such a wet blanket I will tell you what the problem was: after creating the file in TestUtilities.createTemplateFileInProjectAt() the project has to be refreshed or the new file will never be found. Add the following after your resource creation code:

        project.refreshLocal(IResource.DEPTH_INFINITE, null); // You could also use IResource.DEPTH_ONE or IResource.DEPTH_NONE as well.

So in TestUtilities.createTemplateFileInProjectAt() the code above would go at after the creation of the file (don’t forget the CoreException declaration in the method signature as well):

    public static void createTemplateFileInProjectAt(IProject project, String relativePath, String filename) throws IOException, CoreException {
        String templateFilePath = NewWizardMessages.WizardSchemaNewFileCreationPage_Schema_Template_Location;
        InputStream inputStream = null;
        inputStream = Activator.getDefault().getBundle().getEntry(templateFilePath).openStream();

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        
        File tempFile = new File(getAbsolutePathToProject(project) + File.separator + relativePath + File.separator + CustomSchemaSupport.FILENAME);
        FileWriter fileWriter = new FileWriter(tempFile);
        
        String line = null;
        while((line = bufferedReader.readLine()) != null) {
            fileWriter.write(line);
        }
        fileWriter.close();

        // Add this to make the file discoverable.        
        project.refreshLocal(IResource.DEPTH_INFINITE, null);
    }

Creating the file without the use of the Eclipse API effectively makes the file invisible until you tell the system to refresh its view of the underlying file system.

Another way to do this (with much thanks to Raphael Chaves) is to work with Eclipse and just use the IFile.create() method which keeps the view of the file system in sync with Eclipse. In addition to avoiding the need to force a manual refresh, the code becomes much simpler:

    public static void createTemplateFileInProjectAt(IProject project, String relativePath, String filename) throws IOException, CoreException {
        String templateFilePath = NewWizardMessages.WizardSchemaNewFileCreationPage_Schema_Template_Location;
        InputStream inputStream = null;
        inputStream = Activator.getDefault().getBundle().getEntry(templateFilePath).openStream();

        IFolder folder = project.getFolder(SCHEMA_FOLDER_NAME);
        IFile file = folder.getFile(FILENAME);
        file.create(inputStream, false, null); // false means don't create the file if the file already exists
    }

Not as much fun, but then eating your vegetables never is.

Woo hoo. Happy New Year!

About these ads
  1. January 2, 2011 at 3:03 am

    Calling refreshLocal is only necessary if you are creating files directly in the file system (for instance, because your code is not Eclipse-aware). Alternatively, you could have used the resources API directly (IFile.setContents).

  2. January 2, 2011 at 7:18 am

    First you should not swallow exceptions:

    } catch (IOException e) {
    // send back null
    }

  3. cvalcarcel
    January 2, 2011 at 10:01 am

    Ah! I love a new year with challenges! Before I respond directly take into account a couple of things:
    – the above was test code
    – something else, but I can’t remember it right now

    Rafael: A pleasure to meet you! I have not had the need to write across the network so I cannot speak to doing anything else, but writing locally. Since I am writing the file locally (I am using FileWriter using the absolute path of the project as my guide) the call to refreshLocal() makes sense.

    I do like the idea of creating the file using IFile.create() instead of my rather crude use of FileWriter. In fact, I like it so much that I will probably update the above with that code instead.

    Elke: A pleasure to meet you as well.

    About exceptions: they are, well, exceptional. That means that how you handle them depends on how you use them. What you should have gotten me on, but now I’ve fixed so you can’t take credit for it, is that since I was already throwing an IOException I don’t actually need the try/catch in that case. The exception should just bubble up so that JUnit displays the stack trace rather than me try to second guess what just happened. I actually always do that, but I guess I had too much eggnog. Or beer. I don’t remember.

    Or perhaps that is what you meant. You appear to be a man of very few words. :)

    Thank you both for your comments! Happy New Year!

  4. Alex
    February 15, 2012 at 10:51 am

    I’m creating my eclipse plugin, and I’m using your blog as a cookbook/reference, very helpful info!.

    Keep going man.

    Cheers!

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 3,182 other followers

%d bloggers like this: