8
\$\begingroup\$

I have a bunch of simple interfaces like this one (pretty enough formed, but not guarantee)

package com.example.sources;

import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.resources.client.ImageResource.ImageOptions;
import com.google.gwt.resources.client.ImageResource.RepeatStyle;

import com.example.sources.MainSceneResource;
import com.example.sources.Preloadable;

public interface MainSceneResources extends ClientBundle, Preloadable {

    @Source("com/example/sources/css/mainscene.css")
    public MainSceneResource mainSceneCss();

    @Source("com/example/sources/img/panorama.jpg")
    @ImageOptions(repeatStyle = RepeatStyle.None)
    public ImageResource mainSceneBackground();

}

I need to:

  1. remove line with package;
  2. change lines with import (delete the import keyword, whitespaces, semicolon at the end) and add stripped packages with the Factory's method addImport(line);
  3. change Preloadable to Generated
  4. copy other lines without changes with the SourceWriter's method sw.println(line)

Currently my code is like:

BufferedReader reader = new BufferedReader(new InputStreamReader(ris));

String line = null;
try {
    while ((line = reader.readLine()) != null) {
        if (line.contains("package") || line.isEmpty()) {
            continue;
            }
        int index = line.indexOf("import");
        if (index != -1) {
            line = line.substring(index + 6, line.lastIndexOf(";")).trim();
            factory.addImport(line);
            continue;
        }
        if (line.contains("Preloadable")) {
            line = line.replace("Preloadable", "Generated");
        }
        sw.println(line);
    }
} catch (IOException e) {
    throw new UnableToCompleteException();
}

The one more notice is that I can't use SourceWriter method sw.println(line) before Factrory factory.addImport(line);

My most worries are about calling line.contains("pattern") in while-loop. As I know "pattern" will be compiled to Java regex Pattern.class. I'm aware it's not good to compile the same Pattern over and over till the loop ends, but don't know how to do this better. Also I doubt about this line (to strip import lines)

line = line.substring(index + 6, line.lastIndexOf(";")).trim();

Is there a better way to do this?

\$\endgroup\$
4
\$\begingroup\$

Generally what you do is dangerous. More dangerous as you might expect. As soon as you have something odd like a line break in a package or import line, a double semicolon or multiple import statements in a line, the code will break. If your keywords ("package", "import", "Generated") are used somewhere inside the interface, it will break as well (note that these words could appear e.g. in comments).

If you don't want to use a "real" Java parser, there are some things you can do to improve your code: If you don't find a closing semicolon for package or import, add the next line as long as you don't have one - or throw at least a meaningful error. You can also check if you have two semicolons in a package or import line. But I think the most important point is to break your loop in 4 parts in order to make your changes as "local" as possible. The first loop deals with the package, the second with the imports, the third with Generated and the fourth just adds the rest without changing. So your are safe that after a step is done, it can't do any harm to the following code. Another thing you could try is to preprocess the code with some formatter / pretty printer, which could get rid of some quirks.

Before the code gets at least a little bit more secure, I wouldn't care about performance too much. Consider adding some JUnit tests (ask your colleagues for some "mean" input classes - you will be surprised which weird monsters they can imagine - and use the more realistic examples).

\$\endgroup\$
  • \$\begingroup\$ Code of interfaces is always checked by the GWT compiler before the manipulations. It's guaranteed to be a valid java source. I've also thought about multiple statements in a line and keywords. In the future when I can't control all input sources I'm going to make code more secure like a "real" java parser. \$\endgroup\$ – trupanka Jun 28 '11 at 5:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.