Archive for October, 2009

Piping Output Stream to an Input Stream

Tuesday, October 20th, 2009

The Problem

Recently I had to write adapter for some API interface. Implementation was quite usual and the method of interest was void setValue(InputStream). Interface that I had to adapt exposed OutputStream write(), lucky me.

The Solution

First, exposing OutputStream is a bad idea. API client have to push data into the output stream and receiving side must consume bytes at the forced speed or provide potentially huge buffer not to block the client. The ideal solution would be to change the API to accept InputStream: such API requires minimum efforts from the client and allows implementation to extract data at appropriate rate.

So, what could I do to make it work now? Below is a simple solution that essentially collects all bytes in a buffer and then wraps it in input stream:

public OutputStream write() {
  return new ByteArrayOutputStream() {

    public void close() throws IOException {
      super.close();
      try {
        consumer.consume(new ByteArrayInputStream(buf, 0, count));
      } catch (ConsumerException ce) {
        throw new IOException(ce);
      }
    }

  };
}

You can download the complete sample here: iofun.zip.

Java Idioms for Good and Evil

Saturday, October 10th, 2009

Over time programmers learn particular tricks in their programming languages and make some habits. Here is something from my Java collection.

Good Things

Assignment Result

Assignment expression has a result, but many people ignore it. You may use it to improve the code. Consider this example:

class Controller {

  private View view;

  public void setView(View view) {
    this.view = view;
    hookView(view);
  }

  protected void hookView(View view) {...}
}

Method setView() may be written in one line:

public void setView(View view) {
    hookView(this.view = view);
}

The positive effect of this change is not only that you have to type fewer characters. Now you have to read less and so can understand the code faster.

Method Chaining

This idiom is typically used on a library basis. The author of the library that is aware of this idiom designs library API in a way that allows method chaining. In practice this means that instead of returning void you should return this. Here is a conventional code:

  Composite plate = //...
  plate.add(label);
  plate.add(text);
  plate.add(button);

If add() method returns this, and in this case it is a plate, then calls to it could be chained:

  Composite plate = //...
  plate.add(label).add(text).add(button);

The benefits are again less text to type and less code to read.

Map Literal

This is a convenient way to create a one-off map. You fill the map in static initializer:

Collections.unmodifiableMap(new HashMap() {{
  this.put("key1", "value1");
  this.put("key2", "value2");
}});

Commando Pattern

Imagine that you are writing a unit test and have to check value of some private attribute, like currentPosition in java.util.StringTokenizer. But there is no accessor so you can't do it! Here comes a reflection-based hack that penetrates private defense like commando:

StringTokenizer st = //...
Integer currentPosition = null;
try {
  Field f = st.getClass().getDeclaredField("currentPosition");
  f.setAccessible(true);
  currentPosition = (Integer) f.get(st);
} catch (NoSuchFieldException nsfe) {
} catch (IllegalAccessException iae) {
}

Bad Things

'I' In Interface Names

I believe this convention came from C++ since there was no explicit notion of interface and people have to use abstract classes. Prepending their names with 'I' was the way to reassure others that such classes are indeed interfaces. There is no need to do this in Java. Moreover, interfaces should be as clean as possible by definition since they represent API and those 'I's are just noise that makes API harder to comprehend.

So if you a young programmer and prepend 'I's then others may think that you are blindly mimic bad habits. If you are a seasoned programmer then others may think that you are just too old.

False Instanceof

The normal way to check that an object is not an instance of a class is to negate instanceof operator. Some people are frustrated that negation has a higher priority and they have to use parenthesis:

if (!(obj instanceof String)) {
  // ...
}

So they write this check like this:

if (false == obj instanceof String) {
  // ...
}

The problem is not only that it's longer now but it's harder to read. The normal version reads like 'if not obj instance of string' and is close to english prose while the second version is quite far from it.

The counter argument is that the second version is easier to type: you don't have to press Shift key. It is true, but typically we write code once and read it several times later so I would prefer more readable version.

HyperParser: Tolerant HTML Parser

Friday, October 9th, 2009

This code is now a part of the BaseAppKit.

While writing Daily Deviations I've searched for a parser to read HTML markup and extract info about deviations. None was suitable so I've written my own and now share it with you.

Here is a sample project with all sources: Images Extractor

Usage

HyperParser API is modeled after NSXMLParser API. Typically the first step is to create a delegate object that will collect required data from the stream of HTML tokens. In our example we extract src attribute of img elements:

@interface ImagesCollector : NSObject <HyperParserDelegate> {
  NSMutableArray *urls;
}

- (NSArray *)urls;

@end

@implementation ImagesCollector

- (id)init {
  if (self = [super init]) {
    urls = [[NSMutableArray alloc] init];
  }
  return self;
}

- (void)dealloc {
  [urls release];
  [super dealloc];
}

- (void)parser:(HyperParser *)parser
  didStartElement:(NSString *)elementName
  attributes:(NSDictionary *)attributeDict
{
  if ([elementName caseInsensitiveCompare:@"img"] == NSOrderedSame) {
    NSString *imageLink = [attributeDict objectForKey:@"src"];
    if (imageLink) {
      [urls addObject:imageLink];
    }
  }
}

- (NSArray *)urls {
  return urls;
}

@end

The second step is to actually parse a string:

NSString *page = [NSString stringWithContentsOfFile:@"page.html"];
NSLog(@"Page length: %i", [page length]);
ImagesCollector *collector = [[[ImagesCollector alloc] init] autorelease];
HyperParser *parser = [[[HyperParser alloc] initWithString:page] autorelease];
parser.delegate = collector;
[parser parse];
for (NSString *url in [collector urls]) {
  NSLog(url);
}