DigitalJoel

2015/10/06

Iterative Code vs. Reactive Code

Filed under: development, java, rxJava — Tags: , — digitaljoel @ 4:45 pm

At work we have an internal app that downloads a large JSON file and uses angular to create tables and allows for filtering and whatnot.  The user interface is SUPER slow.  Basically unusable, and it didn’t give me the data in the format I needed.  So, I decided to take the giant JSON dump and parse it with a little java program and output the information I need.  The JSON data looks like this:

apps – an ordered list of strings.

gavs – an ordered list of strings.

hosts – an ordered list of strings.

uses – a list of 3-item integer arrays where the first item in the array is the index into the app collection, the second is the index into the gavs collection, and the third is an index into the hosts collection.  Something like [45, 67, 189] would mean that it references the app at the 45th index, the gav at the 67th, and the host at the 189th.

I needed to get a list of all apps that are associated with certain gavs.  So my first pass was an iterative solution. It looked something like this:

public static void main( String... args ) {
    for ( blah : blah ) // stuff that gets the gavIndex I'm interested in...
        for ( List<Integer> use : uses ) {
            // if the index in the gav collection matches the gav that I'm testing now
            if ( gavIndex == use.get(1)) {
                // get the app string from the apps collection so I can show a user friendly
                // app name instead of just an index.
                String app = apps.get(use.get(0));
                // references is a multimap that is storing my apps per gav.
                if ( references.get(app) == null || !references.get(app).contains(module)) {
                    // so put the reference in the multimap if it's not already there.
                    references.put(app, module );
                }
            }
        }
    }
    // code to output my references.
}

Now the reactive code:

public static void main( String... args ) {
    PublishSubject<List<Integer>> subject = PublishSubject.create();
    for ( blah : blah ) // stuff that gets the gavIndex I'm interested in...
        subject
            .filter(use -> shouldInsert( apps, use, gavIndex, module, references))
            .subscribe(use -> references.put(apps.get(use.get(0)), module));
    }
    Observable.from(uses).subscribe(subject);
    // code to output my references.
}
// basically the condition that was inline in the iterative solution.
private static boolean shouldInsert( List<String> apps, List<Integer> use, int gavIndex, String module, Multimap<String, String> references ) {
    Collection<String> currentUses = references.get(apps.get(use.get(0)));
    boolean result = (gavIndex == use.get(1)) && (currentUses == null || !currentUses.contains( module ));
    return result;
}

I get the same result from both processes. The reactive I find interesting because I just set everything up, then when the subject subscribes to the observable it all just goes. I also think the succinctness of the reactive code is actually easier to read.

Are there fewer lines? Not really, and that shouldInsert method sure takes a lot of parameters. Currently it’s not thread safe, but I could get there easily, and then I would expect the reactive version to be faster than the iterative. Finally, the question is, what does rx buy me over java 8 streams in this case? Not really anything, but I don’t have a ton of experience with java 8 streams yet, and sadly I don’t have time to mess with it currently. Anyway, it was interesting to me, and thought it might be interesting to others.

2015/09/07

RxJava concurrency demo application

Filed under: development, java, rxJava — Tags: , , , — digitaljoel @ 2:25 pm

Background

Back when I was in a reading group and had 2 weeks to learn Erlang I wrote a little air traffic control application to highlight the concurrency capabilities of Erlang.  Here is my blog post regarding that.

A few months ago I volunteered to do a presentation on rxJava at my employer’s internal technical conference.  What I didn’t tell them is that I didn’t know anything about it other than it was a current buzz word.  I thought it would be interesting and that giving a presentation on it would be a great reason to learn it.  Fortunately for me, a brilliant co-worker also proposed to present on it so we were paired up together.  I’m not going to lie, he did nearly all the powerpoint work, including the flow of the presentation.  I got to talk about operators (combining, filtering, subscribing) and testing/debugging/error handling.  All in all I thought it went quite well.

Since I had no experience, I decided I needed some application to get up to speed on rxJava.  I wanted to be able to answer questions and have more experience than just having read the documentation before the people attending the session.

So, I decided to write the air traffic control application in java.  Sadly, I don’t know that I could even really read the Erlang anymore, but the ideas are pretty easy to understand.

Enough jabbering about that, let’s got to the code.  I will do some explaining as we go, but you should have some familiarity with reactive concepts.  If you need a primer, head to reactivex.io and spend some time reading.

The Setup

Here’s the premise.  There are airplanes that need to land.  There is a flight tower that directs them where to go.  If two planes enter the same place then they collide.  If an airplane enters the space occupied by the tower then it has landed.  Airspace is represented by a square grid and the tower is in the middle of the grid.  The air traffic controllers are not very smart (but smarter than the Erlang version!)

Here’s how I broke things out.

  • The Radio – Responsible for transmitting messages from the tower to the plane.
  • The Radar – Responsible for broadcasting the position of the planes.
  • The Planes
    • Each plane receives messages from the radar so they can determine if another plane has entered their space (in which case they collide
    • Each plane also receives messages from the radio.  These tell the plane where to move to next.
    • Each plane sends a blip on the radar to broadcast its current location.
  • The Tower
    • Receives blips on the radar with the location of each plane.
    • Sends messages on the radio that tell the plane where to go next.
  • Radar Screen
    • Receives blips from the radar
    • Displays a graph showing where each plane is on the grid.

The Code

The code can be found in it’s fullness at https://github.com/digitaljoel/rxAir. The following does actually contain most of it, but if you want to run things, you’ll want to fetch it from github.

Radio


PublishSubject<RadioMessage> radio = PublishSubject.create();

Ok, this one is simple.  The radio is a PublishSubject for RadioMessages.  A RadioMessage simply contains the target flight number and the location that the target flight should fly to next.  Because it’s a PublishSubject it can subscribe to Observables that emit RadioMessages, and will also pass those through to any subscribers that are observing the radio.

Radar


PublishSubject<Blip> radar = PublishSubject.create();

Another nice, simple one.  The radar is a PublishSubject for Blips.  A Blip contains the id of the blip source (in this case a flight number), and the location of the blip source.  Finally, it contains a blip type, like MOVE, LAND, or CRASH.  It being a PublishSubject here has the same benefits as the Radio.

Tower

Now we start getting into some of the guts and putting rxJava to use.  First, here is the code that creates the Tower.

 // create the tower, which is where the planes try to get to land.
 Tower tower = new Tower(TOWER_LOCATION, radar);
 // and allow the tower to emit on the radio
 Observable.create( tower ).subscribe(radio);

So first we create the tower with a nice, simple constructor.  I went back and forth a few time on how to handle the tower and the radar.  The subscription isn’t a simple one like the one above with the radio.  I decided to encapsulate it within the Tower class.

Here is the bulk of the interesting code within the Tower class:


public class Tower implements Observable.OnSubscribe<RadioMessage>{

  private Pair location;

  Subscriber<? super RadioMessage> radio;
  Observable<Blip.  radar;

  public Tower( Pair location, Observable<Blip> radar ) {
    this.location = location;
    this.radar = radar;

    connectRadar();
  }

  /**
   * Implementation of the OnSubscribe interface
   */
  @Override
  public void call(Subscriber<? super RadioMessage> t) {
    radio = t;
  }

  private void connectRadar() {
    // on a MOVE blip from a plane we will send them information on where to go next.
    radar.filter(b -> b.type == MOVE &amp;amp;&amp;amp; !b.location.equals(location))
        .observeOn(Schedulers.computation())
        .subscribe(b -> {
          if ( !radio.isUnsubscribed()) {
            radio.onNext(new RadioMessage(b.id, getNewCoordinates(b.location)));
          }
        });
  }
}

The interesting part here is in the connectRadar method.  The rxJava APIs are very fluent, but here’s a simple english explanation.

  1. First we only want to see the blips on the radar that are of the MOVE type and that are not within the tower’s location.
  2. We don’t want to handle all these blips on the main thread, so we observe on the computation scheduler.
  3. In onNext we use the current coordinates of the blip and then emit on the radio a message that tells the plane where to go next.

That’s really it for the tower.

Plane

Here is the code that creates the planes:

    long totalSleep = 0;
    // create all the planes.
    for ( int i = 0; i < PLANES; i++ ) { Plane plane = new Plane(i, getNewSpeed(), getStartingPair(GRID_SIZE), TOWER_LOCATION, radar); // subscribe the plane to the radio // if we subscribe on a different thread, then we may not get our first message radio.filter(msg -> msg.flightNumber == plane.flightNumber )
          .observeOn(Schedulers.computation())
          .subscribe( plane );
      // tell the radar to listen to blips from the plane.
      Observable.create(plane).subscribe(radar);
      // rather than start them all at once, they will enter the grid when this Observable calls onNext.
      Observable.timer(totalSleep, TimeUnit.MILLISECONDS)
          .subscribe( n -> plane.takeoff());
      totalSleep += getNextSleep();
    }

I ran into one gotcha on this one.  As you can see by the comment, if I subscribe on a different scheduler then I would occasionally see the case where the plane would send a blip, the tower would receive the blip and send a radio message, all before the plane subscribed to the radio.  Ah the joys of concurrency.  While rxJava makes this a lot easier, there are still all the same concerns when it comes to threaded code.

Another tidbit you’ll see here.  I wanted to create all the planes at once and then have them come onto the grid using a staggered schedule.  To accomplish this I used an Observable.timer that when it fires would tell the plane to take off.  I accumulate the timeout so that each plane takes off some random time after the previous one.

Here are the details of the Plane class:

public class Plane implements Observer<RadioMessage>, Observable.OnSubscribe<Blip> {

  public final int flightNumber;
  private Pair location;
  private Pair towerLocation;
  private int speed;
  private AtomicBoolean flying = new AtomicBoolean(false);

  Observable<Blip> radar;
  Subscription radarSubscription;
  Subscriber<? super Blip> blipSubscriber;

  public Plane( int flightNumber, int speed, Pair startingLocation,
        Pair towerLocation, Observable<Blip> radar ) {
    this.flightNumber = flightNumber;
    this.speed = speed;
    this.radar = radar;
    this.location = startingLocation;
    // when we get to the tower location we have landed.
    this.towerLocation = towerLocation;
  }

  /**
   * Implementation of onNext for the Observer interface.  The way we subscribe
   * means that we will only get RadioMessages that are directed at our flightNumber
   */
  @Override
  public void onNext(RadioMessage m) {
    Observable.timer( speed, TimeUnit.MILLISECONDS)
    .first()
    .subscribe( n -> {
        // when the timer goes off, it calls this onNext message
        if (flying.get()) {
          // if we haven't crashed while traveling to our new location then set our current to the new.
          this.location = m.location;
          if ( this.location.equals(towerLocation) ) {
            land();
          }
          else {
            // if we haven't landed, then send a blip to tell the tower our new location.
            move();
          }
        }});
  }

  /*
   * Implementation of the OnSubscribe interface
  */
  @Override
  public void call( Subscriber<? super Blip> t ) {
    blipSubscriber = t;
  }

  private void sendBlip( Blip blip ) {
    if ( !blipSubscriber.isUnsubscribed()) {
      blipSubscriber.onNext(blip);
    }
  }

  public void takeoff() {
    flying.set(true);
    connectRadar();
    sendBlip( new Blip( flightNumber, location, MOVE ));
  }

  private void land() {
    flying.set(false);
    sendBlip(new Blip(flightNumber, location, LAND));
    radarSubscription.unsubscribe();
  }

  private void move() {
    sendBlip(new Blip(flightNumber, location, MOVE));
  }

  /**
   * Subscribe to the radar
   */
  private void connectRadar() {
    // get blips that are in our airspace that is not us.
    // if we get a blip it must be another airplane that will cause us to crash.
    radarSubscription = radar.filter(b -> b.id != this.flightNumber)
      .filter(b -> b.location.equals(this.location))
      .filter(b -> b.type == MOVE || b.type == CRASH )
      .observeOn(Schedulers.computation())
      .subscribe(blip -> {
          // on any blip on the radar in our space, it will cause us to crash if we are still flying.
          if ( flying.get()) {
            sendBlip(getRadarResponse(blip));
          }
      });
  }

  /**
  * We have received a blip on the radar.  That means someone else has entered our space.
  * Because of that we must crash.
  */
  private Blip getRadarResponse( Blip blip ) {
    // whether landing or crashing we are done with this flight.
    flying.set(false);
    // we will unsubscribe from the radar because once crashed we don't need any more blips
    radarSubscription.unsubscribe();
    // send a crash blip on the radar.  This will notify the plane that hit us that 
    // we were already in this space and cause them to crash also.
    return new Blip( flightNumber, location, Blip.BlipType.CRASH);
  }

The plane class has comments that hopefully explain the bulk of the code, but here are a few notes on it anyway.

First, for brevity I left off the onCompleted and onError methods that would normally be required of an implementation of the Observer interface.

Second, I would have liked this class to implement Observer AND Observer but that’s illegal in java.  This is why I had to pass the radar in to the constructor, so the plane could subscribe to it.  I could have at that point also just had the radar subject subscribe back to the plane, but that made it more tightly coupled.  This way, having the Blip Observable and the Blip Observer separate, the plane doesn’t need to know that it’s implemented as a subject.

One way I may have been able to get around not being able to have the Plane implement Observer twice would be to go to composition.  The Plane could have had an accessor method that would return the Observer and another that would return the Observer.  Then it would only be implementing the OnSubscribe interface.

I should probably also point out that the Tower and the Planes each expect to only have one subscriber.  It should probably be a thread-safe collection of subscribers so that more than one Observer can subscribe.  The PublishSubject helps obviate this in my case, but I’m not sure my way is the best way here.

Ancillary Code

Since my application creates all the planes at once on different schedulers, If I don’t have a mechanism to make the main thread wait for all the planes to complete then the application would start and finish nearly instantly.  To get around this I use a CountDownLatch initialized with the number of planes that we create.  Then we simply subscribe to the radar and look for crash and land events and decrement the latch on those.  Finally, we just wait for the latch to complete and then the program can terminate.  Here’s the code:


// Create a latch so we don't end the program prematurely.
CountDownLatch latch = new CountDownLatch(PLANES);

// subscribe to the radar so we countdown whenever a plane lands or crashes.
radar.filter(b -> b.id != -1 &amp;&amp; (b.type == LAND || b.type == CRASH))
.subscribe(b -> latch.countDown());

// plane creation code here

// complete when all planes have landed or crashed.
latch.await();

Next, we have the radar screen.  This is purely for output.  The Erlang version didn’t have this nicety, but it sure was great for debugging… and entertainment.

public class RadarScreen implements Observer<Blip> {

  private BiMap<Integer, Pair> flightMap = Maps.synchronizedBiMap(HashBiMap.create());
  private Map<Pair, Integer> crashes = Maps.newConcurrentMap();

  private int gridSize;
  private Pair location;

  
  public RadarScreen( int gridSize, Pair location ) {
    this.gridSize = gridSize;
    this.location = location; // location is the location of the tower.
  }

  @Override
  public void onNext(Blip t) {
    if ( t.type == LAND ) {
      // if they are landing just remove by id.
      flightMap.remove(t.id);
    }
    else {
      // remove by location
      flightMap.inverse().remove(t.location);
      if ( t.type == MOVE ) {
        // if they are moving then put them back on the map
        flightMap.put(t.id, t.location);
      }
      else if ( t.type == CRASH ) {
        // if they are crashing do not put them back on the map, but add it to the crashes collection.
        crashes.put(t.location, 10);
      }
    }
    printGraph();
  }

It is a very simple implementation that simply rewrites the entire graph to System.out when a radar event is received.  On my mac I can watch it in the STS console and it looks fairly animated.  Fortunately, since you could subscribe to the radar with anything, you could just as easily put together a swing UI to show the planes.

I left out the implementation that prints the graph (since it’s just creating a StringBuffer and then spitting it to System.out) and I also left out the onCompleted and onError methods.  I also left out some extra code that is used to print asterisks in crash locations.

Lessons Learned

This was quite a fun experiment, and was a great way to learn about reactive programming in general, and rxJava specifically.  My part of the presentation had to do with the operators, debugging, testing, and error handling.  I didn’t build much error handling into this example, but I did get to play with the creation, filtering, and mapping operators, and spent plenty of time testing and debugging.

My first implementation was kind of similar to this implementation, but had a lot more garbage that I just didn’t need.  I had extra layers of Observables and Observers and it was just a mess.  My second implementation was almost purely functional.  It was all contained in one class with a lot of chained calls to map, flatMap, filter, etc.  I kind of liked it, but these both had a fatal flaw.  Both implementations depended on some global state.  This is something I didn’t have in the Erlang implementation because the state was always passed around from function to function.

My final implementation is the one you see here.  It’s not perfect, but I managed to get the global state hidden in the RadarScreen class.  It feels more properly reactive than the first sample, but still has some of the strengths of object oriented programming using the encapsulation of the plane, tower, and radar screen objects.  I’ve learned plenty of times that whatever you first implement with a new technology is just not going to be right.  I’m sure there are holes in this project, things that could have been done differently, and perhaps things that a reactive pro will simply look at and say, “huh?!” but in any case, it gave me a good start.  Here are a few things I learned:

  1. Reactive code is still concurrent code.  Treat it as such
  2. System.out and log.debug are your friends.
  3. Being able to subscribe to an Observable simply for debug purposes is really awesome.  I did this a couple times with the subjects I created just so I could validate the messages going through.  For instance when the message would come through the radio but would not be received by the plane because the plane hadn’t subscribed yet.
  4. If you can’t subscribe with a purely debug Observer then doOnNext is also really awesome.  See #3.
  5. Reactive programming is mind bending for someone with 15 years of experience in core java.  You have to start thinking a little bit more like Javascript and less like java
  6. Java 8 lambdas are really awesome.
  7. There are a lot of ways to do the same thing with rxJava.
  8. I want to do more reactive programming.

2015/03/18

How to make Jackson serialize null strings differently than null Objects

Filed under: development — Tags: , , , , — digitaljoel @ 3:36 pm

We’ve got an API.  It uses a certain technology to write JSON data, and this certain technology writes null strings as empty string (“”), but writes null objects as ‘null’.  It’s in production, and therefore changes to it need to be backward compatible.  Jackson is awesome. We want to replace “certain technology” with Jackson.

My first thought was that I would write a custom StringSerializer and associate it with the String type and then whenever a String is null I would output empty string instead of null and poof, done.  Sadly, in Jackson, if the value is null it will always call the NullValueSerializer instead of the Serializer that is configured for the type of field that contains the null value.

So, how to overcome this conundrum?  It can still be approached with a custom serializer implementation, but you also need to touch the SerializerProvider.  Here’s a quick solution we threw together that appears to be working.

// We need to customize the DefaultSerializerProvider so that when it is looking for a NullSerializer it
// will use one that is class sensitive, writing strings as "" and everything else using the default value.
public static class CustomNullStringSerializerProvider extends DefaultSerializerProvider {

  // A couple of constructors and factory methods to keep the compiler happy
  public CustomNullStringSerializerProvider() { super(); }
  public CustomNullStringSerializerProvider(CustomNullStringSerializerProvider provider, SerializationConfig config,
    SerializerFactory jsf) {
    super(provider, config, jsf);
  }
  @Override
  public CustomNullStringSerializerProvider createInstance(SerializationConfig config,
    SerializerFactory jsf) {
    return new CustomNullStringSerializerProvider(this, config, jsf);
  }

  // This is the interesting part.  When the property has a null value it will call this method to get the
  // serializer for that null value.  At this point, we have the BeanProperty, which contains information about
  // the field that we are trying to serialize (including the type!)  So we can discriminate on the type to determine
  // which serializer is used to output the null value.
  @Override
  public JsonSerializer<Object> findNullValueSerializer(BeanProperty property) throws JsonMappingException {
    if (property.getType().getRawClass().equals(String.class)) {
      return EmptyStringSerializer.INSTANCE;
    } else {
      return super.findNullValueSerializer(property);
    }
  }
}

// This is our fancy serializer that takes care of writing the value desired in the case of a null string.  We could
// write whatever we want in here, but in order to maintain backward compatibility we choose the empty string
// instead of something like "joel is awesome."
public static class EmptyStringSerializer extends JsonSerializer<Object> {
  public static final JsonSerializer<Object> INSTANCE = new EmptyStringSerializer();

  private EmptyStringSerializer() {}

  // Since we know we only get to this seralizer in the case where the value is null and the type is String, we can
  // do our handling without any additional logic and write that empty string we are so desperately wanting.
  @Override
  public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
    throws IOException, JsonProcessingException {

    jsonGenerator.writeString("");
  }
}

Now, when we are configuring the ObjectMapper we can simply call setSerializerProvider and give it our custom provider and voila.

2014/01/10

Exposing a read-only view of a Spring-MVC web service

Alright, so this is actually more flexible than just a read-only view, but that was the case that prompted me to play around with things so that’s where I’m starting. I was partially inspired by a co-worker’s blog entry regarding creating resource filters with jersey and jaxrs 2.0.

So down to the scenario. I have a simple CRUD webservice that I’ve implemented in Spring-MVC. For my demonstration I used Spring Boot, but you can do it any way you want. One key is that this solution depends on a new feature found in Spring Framework version 4.0.

In my webservice I have a @Controller that has @RequestMappings for GET, PUT, POST, and DELETE, following the normal REST semantics for each method. Now, I have this webservice securely deployed in my production environment and all of my internal services can hit it and everything is awesome.

Now let’s pretend I want to expose some of the resources on the big, bad internet. I want to expose all the GET resources so my front end developers can read the information and put it in a web page, or so my mobile apps can get at it, but I don’t really want to expose the ability for them to create, update, or delete information. Now I’ve got a couple of options.

Option 1

I create a new webservice.  It shares the dependencies of the original so it has access to all the same services, but the controller doesn’t contain any RequestMappings other than the GET resources I want to expose.  This is very secure because I have total control over what is available.  IF the original service was designed appropriately so the Controllers don’t contain any business logic then you can easily reuse all of the logic in the previous webservice.  If not, then it’s a good opportunity to get that done I guess.  On the downside, you now have two artifacts to maintain and deploy.

Option 2

I create a webservice that will proxy requests from the big, bad internet and send them to my internal webservice.  The proxy returns a 404 for any resource/method that should not be exposed, and forwards other requests on to the internal webservice.  Again, my service is secure and I can manage which of the resources are exposed.  Also, again, I have two deployables, and this time they aren’t nearly as related as they were before.  The proxy can be very thin, possibly something as simple as nginx or apache with appropriate rules.

Option 3

This is the option I will explore.  With this option, I modify my webservice so that it can be deployed internally AND externally and lock down the resources that shouldn’t be exposed to the public without having to create a separate deployable artifact.  We will simply annotate those request handlers that should be exposed to the public, basically forming a white-list, and all those that are not explicitly exposed will be restricted from view when certain conditions are met.

In addition, this solution will automatically apply a Jackson JsonView to restrict which properties of the data are exposed, not just which request mappings are exposed.  This will allow us to give a restricted view of the response for the general public on the big bad internet, and the full data for those hitting our internal deployment of the webservice.  We would still be deploying to two environments, one for the public and one for internal, but it would be the same artifact in both places.

First, we are going to use the new @Conditional annotation that was introduced with Spring 4.0.  It allows you to conditionally create a Spring bean.  We will use conditionally defined beans to modify the behavior of the application at runtime.

To The Code

First, the Condition that allows us to change the behavior of the application without having to change any code. My condition is based on the IP address assigned to the server. You could modify the condition to whatever fits your needs. Maybe it checks an environment variable or something. It’s important to note that this condition is evaluated when the bean is created, so if it’s a singleton bean it’ll only be evaluated once. If you are looking to have the condition depend on something from the client then it would probably have to be a request scoped bean, but I haven’t checked to see if that actually works or not. It seems like it should.

/**
 * Condition to check if we are in production or not.
 */
public class ProductionCondition implements Condition {

  @Override
  public boolean matches(ConditionContext context, AnnotatedTypeMetadata meta) {
    Enumeration ifaces;
    try {
      ifaces = NetworkInterface.getNetworkInterfaces();
      while ( ifaces.hasMoreElements()) {
        NetworkInterface iface = ifaces.nextElement();
        Enumeration addresses =  iface.getInetAddresses();
        while ( addresses.hasMoreElements()) {
          InetAddress address = addresses.nextElement();
          // Set whatever your public, production IP Address space is here!
          if ( address.getHostAddress().startsWith("192.168" )) {
            // If we match, then return true so the bean annotated with this conditional will be created.
            return true;
          }
        }
      }
    }
    catch (SocketException e) {
    }
    return false;
  }
}

Now we can use the above Condition to conditionally create Spring beans.

Here’s my Spring Boot application.  It also defines other beans for my spring-data-jpa repositories, but those aren’t relevant to what we are doing so I’ve left them out.

@Configuration
@ComponentScan
@EnableAutoConfiguration
@EnableJpaRepositories
public class Application {

  public static void main (String[] args ) {
    SpringApplication.run(Application.class, args );
  }

  @Configuration
  @Conditional(ProductionCondition.class)
  static class WebConfig extends WebMvcConfigurerAdapter {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter> converters) {
      MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
      ObjectMapper mapper = new ObjectMapper() {
        private static final long serialVersionUID = 1L;
        @Override
        protected DefaultSerializerProvider _serializerProvider(SerializationConfig config) {
          return super._serializerProvider(config.withView(Views.Public.class));
        }
      };
      mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);
      converter.setObjectMapper(mapper);
      converters.add(converter);
    }
  }

  /**
   * Only create this bean if we are in "production" mode.
   * @return
   */
  @Bean
  @Conditional(ProductionCondition.class)
  public MappedInterceptor publicHandlerInterceptor() {
    return new MappedInterceptor(null, new PublicHandlerInterceptor());
  }

  // Other beans here for JPA configuration
}

Notice that in the application I have two @Conditional beans. One is a new HandlerInterceptor that I’ll show in a second. The other is a full @Configuration. Because the publicHandlerInterceptor @Bean definition returns a MappedInterceptor it will automatically be configured within the Spring MVC application. If it returned a HandlerInterceptor then more work would have to be done to register it with the Spring MVC application.

Secondly, notice that the Conditional Configuration class extends the WebMvcConfigurerAdapter for allowing me to easily configure Spring MVC-type functionality. Sadly, configuring a custom Jackson ObjectMapper in Spring is much more painful (IMO) than it ought to be, so I’m going to get off on a bit of a tangent. Skip to the next section if you are confident in your ObjectMapper abilities.

ObjectMapper Tangent

It would be fantastic if I could configure the ObjectMapper used for a @ResponseBody by simply defining a @Bean named objectMapper and be good to go. Sadly, that’s not the case. I had to add the MessageConverter in the configuration, and set the ObjectMapper for that MessageConverter. Now, here’s the rub. I kept trying to make my configuration changes to the ObjectMapper by calling getSerializationConfig().blah(). Jackson SerializationConfig is immutable Calling getSerializationConfig() and then all of the handy .with(MappingFeature) or whatever just doesn’t work because it simply returns a new instance of SerializationConfig, but doesn’t modify the one that is in the ObjectMapper. You can see my learning process for this at StackOverflow

Back to the Show

So, the reason I needed to modify the ObjectMapper configuration was so that I could make it always use a given Jackson JsonView for every @ResponseBody encountered. The custom implementation of the ObjectMapper I pasted was the first way I found to configure it to always use the JsonView I specified, otherwise I had to call writeWithView on the writer, and I wasn’t sure where to do that. This configuration gives us the white-list of data properties that should be serialized in each response.

To use it, simply annotate the object returned as your @ResponseBody with the @JsonView annotation from Jackson, something like:

  @JsonView(value={Views.Public.class})
  public String getName() {
    return name;
  }

Securing the RequestMappings

The Application configuration has a conditional bean for a HandlerInterceptor, which looks like this:

public class PublicHandlerInterceptor extends HandlerInterceptorAdapter {
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    HandlerMethod method = (HandlerMethod)handler;
    if ( method.getMethodAnnotation(Public.class) != null ) {
      return true;
    }
    response.setStatus(404);
    return false;
  }
}

This HandlerInterceptor will be evaluated for every RequestMapping. Here, we look at the actual method that is being called to handle the request. If it is annotated with our custom @Public annotation, then we allow the request to proceed by returning true from the HandlerInterceptor. If it isn’t, then we return false and send a 404 to the client.

Finally, here’s the Public annotation definition

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Public {}

And its usage:

  @Public
  @RequestMapping(method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON)
  public @ResponseBody Iterable getCollection(
    @RequestParam(value="ids", required=false) List ids,
    @RequestParam(value="limit", required=false, defaultValue="100") int limit ) {
      // lookup a collection of MyObjects and return them
  }

  @RequestMapping( value="/{id}", method=RequestMethod.PUT, consumes=MediaType.APPLICATION_JSON, produces=MediaType.APPLICATION_JSON)
  public @ResponseBody MyObject putValue(@PathVariable Long id, @RequestBody MyObject d ) {
    // do some things to update an object and return the representation of the updated object
  }

With this in place, I’m able to deploy my webservice (with spring-boot it’s just a jar that contains embedded tomcat!) and run it without any further alterations. The getCollection method would be available in both deployment locations. The putValue handler would only be available in those deployment locations that do NOT match the condition I have specified, so only those that are visible internally. The representation of MyObject is appropriate for the deployment location without any further changes to the webservice either. I merely select the properties of MyObject that I want exposed publicly and annotate them with the appropriate JsonView.

A white-list approach ensures that nothing slips through the cracks to the big, bad internet just because a developer forgot to restrict it. Instead, they must evaluate each request handler and data property and explicitly expose it in the public view.

I could have had my proof of concept developed and tested in under 2 hours had I not run into my difficulties configuring the ObjectMapper. That’s a lesson I won’t soon forget though. I tested all this by making the condition match my IP address when I was connected to my work VPN. When I started the application up and I was connected it would restrict the request handlers and the serialized properties. If I was not connected I could execute any method and would see all of the data properties.

It’s probably not perfect a perfect solution. Does such a thing exist? The one question I’ve thought of is what happens if my code is already using JsonViews? I’m not sure how it would play together. Nevertheless it is an interesting exploration of the capabilities of the @Conditional annotation and HandlerInterceptors.

2012/11/23

Eclipselink static weaving

Filed under: development, eclipse, java — Tags: , , — digitaljoel @ 11:26 pm

I’m playing with a new project and decided to get eclipselink static weaving working in this one. I started on the official eclipselink project documentation on the subject. That’s nice and all, but it doesn’t say anything about getting the weaving to work with maven or eclipse. I really wanted both. Here’s what I did.

First, in persistence.xml you should add the following property:

    <properties>
      <property name="eclipselink.weaving" value="static" />
    </properties>

My maven project has several modules. domain-api contains the entity definitions. domain-impl contains the code for interacting with the database. That means that my persistence.xml is contained in domain-impl and the @Entity classes are in domain-api. That’s alright. To get this all working I decided to use the command line option rather than use the ant task.

The weaving needs to take place on the entities, so the weaving step is placed in the domain-api pom.xml. Within build/plugins I added this plugin.

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.2.1</version>
        <executions>
          <execution>
            <id>weave-classes</id>
            <phase>process-classes</phase>
            <goals>
              <goal>java</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <mainClass>org.eclipse.persistence.tools.weaving.jpa.StaticWeave</mainClass>
          <commandlineArgs>-classpath %classpath -loglevel FINE -persistenceinfo ${basedir}/../domain-impl/src/main/resources ${basedir}/target/classes ${basedir}/target/classes</commandlineArgs>
        </configuration>
      </plugin>

That’ll run the java program to weave the class files in place. Note that my -persistenceinfo argument points to ../domain-impl/src/main/resources. That’s because the StaticWeave class will look for META-INF/persistence.xml within that directory, and my persistence.xml is contained in the domain-impl module, not within domain-api. If you are using maven resource filtering on your persistence.xml this will cause a problem since domain-impl builds after domain-api. That’s not a problem in my case so I’m going to be lazy and not address it.

Once you have that in your pom you should be able to do a mvn clean install and see output something like:

[INFO] --- exec-maven-plugin:1.2.1:java (weave-classes) @ domain-api ---
[EL Config]: metadata: 2012-11-23 23:15:42.798--ServerSession(1166215941)--Thread(Thread[org.eclipse.persistence.tools.weaving.jpa.StaticWeave.main(),5,
org.eclipse.persistence.tools.weaving.jpa.StaticWeave])--
The access type for the persistent class [class com.xyg.model.JoelTest] is set to [FIELD].

I added line breaks for formatting. Anyway, that kind of output means things are working.

Sadly, Eclipse’s maven integration isn’t smart enough to figure this part of the pom out. If we tell Eclipse to ignore this part of the build then the classes won’t get weaved and it’s likely that if you try to run the project from within eclipse it’s not going to work properly. Fortunately, we can work around this.

Within the same pom (in my case, in domain-api) you can add another plugin. This plugin is NOT within the plugins element, but is within a pluginManagement element. You can get eclipse to generate the entry for you by telling it to ignore the execution when it tells you it has an error because it has no lifecycle mapping for the given execution. When you do that it’ll generate an xml block in your pom.xml that will look like this:

    <pluginManagement>
      <plugins>
        <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
        <plugin>
          <groupId>org.eclipse.m2e</groupId>
          <artifactId>lifecycle-mapping</artifactId>
          <version>1.0.0</version>
          <configuration>
            <lifecycleMappingMetadata>
              <pluginExecutions>
                <pluginExecution>
                  <pluginExecutionFilter>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>exec-maven-plugin</artifactId>
                    <versionRange>[1.2.1,)</versionRange>
                    <goals>
                      <goal>java</goal>
                    </goals>
                  </pluginExecutionFilter>
                  <action>
                    <execute/>
                  </action>
                </pluginExecution>
              </pluginExecutions>
            </lifecycleMappingMetadata>
          </configuration>
        </plugin>
      </plugins>
    </pluginManagement>

The version eclipse generates will say something like <ignore></ignore> in the action section of this configuration. If you simply change that to <execute/> then eclipse will execute it. It will execute it every time, even on incremental builds, so hopefully it isn’t too intrusive. I’m just getting started on this project so I don’t have many entity classes yet, but if there’s an issue I’ll get back and update this post.

With this configuration I’m able to execute my integration tests from the command line and I’m also able to run the tests and launch the webapp from within eclipse, and I don’t incur the runtime penalty of dynamic weaving.

2012/10/08

Jackson Mixins

Filed under: development, java — Tags: , , — digitaljoel @ 8:21 pm

You are working with a third party library. You need to serialize an object from that library to JSON. Or, in my case, I needed to serialize an implementation of an interface defined in the third party library. In any case you can’t modify the class you need to serialize, but you also need to change the way the class is mapped. Jackson provides a great mechanism to work around this using what they call MixIns.

Let’s say you are given this:

public interface ThirdPartyInterface {
  long getItemID();
  float getValue();
}

For some reason beyond your control, you need to use id instead of itemID in the JSON as the key for getItemID. To make things even more awesome, you need to have quotes around the itemID and the value, but you don’t want quotes around EVERY numeric field, just those two. With Jackson, I create my mixin interface, and I provide the Jackson annotations that I would like to apply on the instances of the ThirdPartyInterface to my new one.

public interface MyMixin {
  @JsonProperty("id")
  @JsonSerialize(using=ToStringSerializer.class)
  long getItemID();

  @JsonProperty("value")
  @JsonSerialize(using=ToStringSerializer.class)
  float getValue();
}

Now you can see that I have the JsonProperty annotations in there to change the name of the key, and I have the JsonSerialize annotation in there, using the Jackson builtin ToStringSerializer to convert the long and float values into Strings, which will ensure they are quoted in the JSON output.

In order to use my Mixin, I configure the ObjectMapper to do so as follows.

  ObjectMapper mapper = new ObjectMapper();
  mapper.getSerializationConfig().addMixInAnnotations(ThirdPartyInterface.class, MyMixin.class);

In my case, I have several implementations of the ThirdPartyInterface and configuring the mixin as above applies to all implementations. Pretty slick.

2011/06/15

Spring ConverterFactory Implementation

Filed under: java, spring — Tags: , , , — digitaljoel @ 10:12 pm

In my Spring MVC 3 based application I had recently implemented a few Converters for some of my JPA based data objects. It started with one, then another, and so on. By the time I got around to adding my fourth converter to the spring configuration file I knew it was time to pull it out and abstract it a bit. Thankfully, Spring allows you to implement a ConverterFactory that is responsible for creating the converters for some types.

Each of my entities extend an abstract base class that looks basically like this

@MappedSuperclass
public abstract class DataObjectAbstract<K extends Serializable>
        implements DataObject<K>
{
    protected transient String[] excludedEqualsFields = new String[] { "key", "version" };

    @Version
    protected int version;

    @Override
    public boolean equals( Object that )
    {
        return EqualsBuilder.reflectionEquals( this, that, excludedEqualsFields );
    }

    @Override
    public int hashCode()
    {
        return HashCodeBuilder.reflectionHashCode( this, excludedEqualsFields );
    }

    @Override
    public String toString()
    {
        return ToStringBuilder.reflectionToString( this, ToStringStyle.MULTI_LINE_STYLE );
    }
}

The DataObject interface simply declares a getKey and setKey method.

So, in my Spring MVC Controller methods I was originally accepting a String or Long, then using my own data access objects to lookup the entities I needed. The next iteration in my implementation was to implement the Converters as I mentioned above. That was very simple and worked well, but having many data objects I didn’t want to copy that implementation over and over again. This is where the ConverterFactory comes in. Here’s my implementation:

@Component
public class DataObjectConverterFactory
        implements ConverterFactory<String, DataObject<Long>>
{
    @PersistenceContext
    EntityManager em;

    @Override
    public <T extends DataObject<Long>> Converter<String, T> getConverter( Class<T> type )
    {
        return new GenericLongKeyedDataObjectConverter<T>( type, em );
    }
}

The ConverterFactory interface is basically as simple as the Converter interface. The Class<T> type parameter to the getConverter method tells us what type we are going to convert to.  One option from here is to have a big nasty if/else statement with a bunch of instanceof methods that create a new Converter.  I thought about doing this and passing in the appropriate data access object and performing the lookup.  That would be only two classes and then I could convert all of my DataObjects, but I didn’t like the idea of a bajillion instanceof statements.  So you can see I implemented a GenericLongKeyedDataObjectConverter which takes the target type and the EntityManager as a parameters.  Here’s the implementation of the generic converter class:

/**
 * A generic converter used for converting from a string representation of an entity key to the DataObject itself.
 *
 * @param <T> The type that is to be converted to.
 */
public class GenericLongKeyedDataObjectConverter<T extends DataObject<Long>>
        implements Converter<String, T>
{
    private Class<T> type;
    private EntityManager em;

    /**
     *
     * @param type An instance of Class for the type being converted to
     * @param em EntityManager used to perform the lookup.
     */
    public GenericLongKeyedDataObjectConverter( Class<T> type, EntityManager em )
    {
        this.type = type;
        this.em = em;
    }

    @Override
    public T convert( String stringKey )
    {
        Long key = Long.parseLong( stringKey );
        return em.find( type, key );
    }
}

An extremely simple parameterized class implementation of the Converter interface. Here, with no use of instanceof, I’m creating the appropriate converter implementation for all of my persisted classes.  If you have a group of objects that you want converted and they all inherit from a base class, a ConverterFactory may be a better solution than implementing a bunch of converters manually.

Finally, here’s the bean xml configuration:

<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <ref bean="dataObjectConverterFactory" />
        </list>
    </property>
</bean>

Notice that we reference the dataObjectConverterFactory bean, but I never defined it in my xml config.  That’s because I used the @Component annotation on my implementation class.

2011/04/05

Get the “Next” value in a Java Enum

Filed under: development, java — Tags: — digitaljoel @ 10:32 pm

Java Enums. An awesome addition to Java 1.5 so we could avoid using public static ints for that purpose. I’ve been using them for some time with success and never noticed one deficiency until now. You can get the ordinal of an enum value with the ordinal() method. That is basically the index in the order the values were declared. So, if your enum look something like this:

 public enum Planet { MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE }

In this case, MERCURY would have an ordinal of 0, then VENUS 1, and so forth. Now, what if you want to iterate through them? You can get all the values of an enumerated type as an array using the values() method. Cool, right? Well, what if I don’t want to iterate through them, but I want to simply progress from one to the next. It would be cool if math operators (like + and -) would let you go from one to the next, but that’s not the case. I had a need to go from one to the next, so I changed my enum by adding the following method.

 private enum Planet { MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE;
    public Planet getNext() {
      return this.ordinal() < Planet.values().length - 1
          ? Planet.values()[this.ordinal() + 1]
          : null;
    }
  }

Now, if I do Planet.MERCURY.getNext() I would get VENUS. This takes advantage of the ordinal of each entry (which you cannot assign in any other way than the order in which you declare the enum values) and the values method, indexing into the values array to get the next value. If you attempt to go off the end, it’ll return null. It would be simple to make it wrap instead if that makes sense for your case. It would also be trivial to take this and implement a “getPrevious” if you have a need to go in reverse.

2011/03/17

How to create a custom taglib containing an EL function for JSP

Filed under: java — Tags: , — digitaljoel @ 10:49 pm

At some point in your use of JSP, there’s something you’re going to need to do for which you can’t find a spring or jstl tag. In that case, you can create a custom function in your custom tag library. It sounds more difficult than it is. All you will need is a tag library descriptor, and your class that implements the function. That’s about it. Here’s my TLD file.

<taglib xmlns="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" 
    version="2.0">

    <tlib-version>2.0</tlib-version>
    <uri>http://www.your-domain.com/taglib</uri>

    <function>
        <name>doMyStuff</name>
        <function-class>com.mydomain.util.ElFunctions</function-class>
        <function-signature>java.lang.String doMyStuff( java.util.Collection )</function-signature>
    </function>
</taglib>

This file should be placed in your WEB-INF directory. In the function-signature, be sure to use fully qualified names.

Next is the class that implements the function.

package com.mydomain.util.ElFunctions;

import java.util.Collection;

/**
 * Functions for use in expression language in the jsp views.
 */
public class ElFunctions
{

    /**
     * This is the function that is called by the Expression Language processor.  It must be static.
     * @param myparam
     * @return
     */
    public static String doMyStuff( Collection<SomeType> myparam )
    {
        // do stuff here and return the results
    }
}

Finally, just reference the function in my jsp file.

<%-- where you declare your taglibs, include this one, which references the tld we created in the first step. --%>

<%@ taglib prefix="my" uri="/WEB-INF/my.tld" %>

<!-- more html and whatever, in my case I'm using spring:message to output the results of my method call -->

<spring:message text="${my:doMyStuff(bean.collection)}" />

The call to ${my:doMytuff(bean.collection)} causes the EL processor to call my function when it evaluates that snippet. In this case, ‘bean’ would be some java bean available to the view, and ‘collection’ would be a property on the bean that returns the collection expected as input to doMyStuff.

2011/02/17

Java Equals Implementation Performance

Filed under: java — Tags: , — digitaljoel @ 4:13 pm

I had some questions about various implementations of the equals (and by association hashcode) methods in Java. I recently implemented a solution in a project I’m working on that uses Apache’s EqualsBuilder in order to create a simple, elegant looking implementation. Knowing that the solution used reflection, and that equals may be called a lot more than you would think. So, I implemented a little test today in order to see the performance of various implementations. The contenders are the equals method generated by the Eclipse IDE, Apache Commons EqualsBuilder implementation using append, and also using reflection, and finally Pojomatic.

Here’s the source of the test

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.pojomatic.Pojomatic;
import org.pojomatic.annotations.AutoProperty;

public class EqualsTest {

  // how many objects we want to create
  static long count = 10000;
  // seed for our random number generator so all tests get the same variation
  static long seed = 12345;
  // range of variation in the values for our objects
  static int variation = 15;
  // how many times equals was called from the eclipse method
  static long plainCounter = 0;
  // how many times equals was called from the reflection method
  static long reflectCounter = 0;
  // how many times equals was called from the append method
  static long appendCounter = 0;
  // how many times equals was called from the pojomatic method
  static long pojomaticCounter = 0;
  // how many times equals was called from the broken method.
  static long brokenCounter = 0;

  public static void main(String[] args) {
    EqualsTest test = new EqualsTest();
    System.gc();
    test.testPlainEquals();
    System.gc();
    test.testAppendEquals();
    System.gc();
    test.testReflectEquals();
    System.gc();
    test.testPojomaticEquals();
    System.gc();
    test.testBrokenEquals();
  }

  // Do our little test that calls equals a lot of times.
  private void testSomething(List<Object> objects, Object object) {
    for (Object o : objects) {
      if (o.equals(object)) {
        return;
      }
    }
    objects.add(object);
  }

  // Test the performance of equals as implemented using pojomatic
  // http://pojomatic.sourceforge.net/pojomatic/index.html
  private void testPojomaticEquals() {
    Random rand = new Random(seed);
    List<Object> list = new ArrayList<Object>();
    long start = System.currentTimeMillis();
    for (long i = 0; i < count; i++) {
      String s = "asdf";
      long suffix = i * rand.nextInt(variation);
      MyObjectPojomatic obj = new MyObjectPojomatic(s + suffix, s + (suffix + 1), s + (suffix - 1),
          suffix, suffix + 1, suffix - 1);
      testSomething(list, obj);
    }
    long end = System.currentTimeMillis();
    System.out.println("Time taken for pojomatic is " + (end - start) + "ms" + " set size is "
      + list.size() + " calls = " + pojomaticCounter);
  }

  // test a broken implementation of equals to show a difference in the set size and total calls
  private void testBrokenEquals() {
    Random rand = new Random(seed);
    List<Object> list = new ArrayList<Object>();
    long start = System.currentTimeMillis();
    for (long i = 0; i < count; i++) {
      String s = "asdf";
      long suffix = i * rand.nextInt(variation);
      MyObjectBroken obj = new MyObjectBroken(s + suffix, s + (suffix + 1), s + (suffix - 1),
          suffix, suffix + 1, suffix - 1);
      testSomething(list, obj);
    }
    long end = System.currentTimeMillis();
    System.out.println("Time taken for broken is " + (end - start) + "ms" + " set size is "
      + list.size() + " calls = " + brokenCounter);
  }

  // test EqualsBuilder.reflectionEquals from apache commons.
  // http://commons.apache.org/lang/api-2.6/org/apache/commons/lang/builder/EqualsBuilder.html
  private void testReflectEquals() {
    Random rand = new Random(seed);
    List<Object> list = new ArrayList<Object>();
    long start = System.currentTimeMillis();
    for (long i = 0; i < count; i++) {
      String s = "asdf";
      long suffix = i * rand.nextInt(variation);
      MyObjectReflect obj = new MyObjectReflect(s + suffix, s + (suffix + 1), s + (suffix - 1),
          suffix, suffix + 1, suffix - 1);
      testSomething(list, obj);
    }
    long end = System.currentTimeMillis();
    System.out.println("Time taken for reflection is " + (end - start) + "ms" + " set size is "
      + list.size() + " calls = " + reflectCounter);
  }

  // test EqualsBuilder.append equals from apache commons.
  // http://commons.apache.org/lang/api-2.6/org/apache/commons/lang/builder/EqualsBuilder.html
  private void testAppendEquals() {
    Random rand = new Random(seed);
    List<Object> list = new ArrayList<Object>();
    long start = System.currentTimeMillis();
    for (long i = 0; i < count; i++) {
      String s = "asdf";
      long suffix = i * rand.nextInt(variation);
      MyObjectAppend obj = new MyObjectAppend(s + suffix, s + (suffix + 1), s + (suffix - 1),
          suffix, suffix + 1, suffix - 1);
      testSomething(list, obj);
    }
    long end = System.currentTimeMillis();
    System.out.println("Time taken for append is " + (end - start) + "ms" + " set size is "
      + list.size() + " calls = " + appendCounter);
  }

  // Test the equals method as generated by Eclipse IDE
  // http://eclipse.org/
  private void testPlainEquals() {
    Random rand = new Random(seed);
    List<Object> list = new ArrayList<Object>();
    long start = System.currentTimeMillis();
    for (long i = 0; i < count; i++) {
      String s = "asdf";
      long suffix = i * rand.nextInt(variation);
      MyObjectPlain obj = new MyObjectPlain(s + suffix, s + (suffix + 1), s + (suffix - 1), suffix,
          suffix + 1, suffix - 1);
      testSomething(list, obj);
    }
    long end = System.currentTimeMillis();
    System.out.println("Time taken for plain is " + (end - start) + "ms" + " set size is "
      + list.size() + " calls = " + plainCounter);
  }

  // Object that uses EqualsBuilder.append for equals.
  public class MyObjectAppend {
    public String s1;
    public String s2;
    public String s3;
    public Long l1;
    public Long l2;
    public Long l3;

    public MyObjectAppend(String a, String b, String c, Long d, Long e, Long f) {
      s1 = a;
      s2 = b;
      s3 = c;
      l1 = d;
      l2 = e;
      l3 = f;
    }

    @Override
    public boolean equals(Object obj) {
      appendCounter += 1;
      if (obj instanceof MyObjectAppend) {
        MyObjectAppend that = (MyObjectAppend) obj;
        EqualsBuilder builder = new EqualsBuilder();
        builder.append(this.s1, that.s1);
        builder.append(this.s2, that.s2);
        builder.append(this.s3, that.s3);
        builder.append(this.l1, that.l1);
        builder.append(this.l2, that.l2);
        builder.append(this.l3, that.l3);
        return builder.isEquals();
      }
      return false;
    }

    @Override
    public int hashCode() {
      HashCodeBuilder builder = new HashCodeBuilder();
      builder.append(this.s1);
      builder.append(this.s2);
      builder.append(this.s3);
      builder.append(this.l1);
      builder.append(this.l2);
      builder.append(this.l3);
      return builder.toHashCode();

    }
  }

  // Object that uses EqualsBuilder.reflectEquals for the implementation
  public class MyObjectReflect {
    public String s1;
    public String s2;
    public String s3;
    public Long l1;
    public Long l2;
    public Long l3;

    public MyObjectReflect(String a, String b, String c, Long d, Long e, Long f) {
      s1 = a;
      s2 = b;
      s3 = c;
      l1 = d;
      l2 = e;
      l3 = f;
    }

    @Override
    public boolean equals(Object obj) {
      reflectCounter += 1;
      return EqualsBuilder.reflectionEquals(this, obj);
    }

    @Override
    public int hashCode() {
      return HashCodeBuilder.reflectionHashCode(this);
    }
  }

  // Object that users pojomatic's equals implementation
  @AutoProperty
  public class MyObjectPojomatic {
    public String s1;
    public String s2;
    public String s3;
    public Long l1;
    public Long l2;
    public Long l3;

    public MyObjectPojomatic(String a, String b, String c, Long d, Long e, Long f) {
      s1 = a;
      s2 = b;
      s3 = c;
      l1 = d;
      l2 = e;
      l3 = f;
    }

    @Override
    public boolean equals(Object obj) {
      pojomaticCounter += 1;
      return Pojomatic.equals(this, obj);
    }

    @Override
    public int hashCode() {
      return Pojomatic.hashCode(this);
    }
  }

  // Object with a broken equals implementation.
  public class MyObjectBroken {
    public String s1;
    public String s2;
    public String s3;
    public Long l1;
    public Long l2;
    public Long l3;

    public MyObjectBroken(String a, String b, String c, Long d, Long e, Long f) {
      s1 = a;
      s2 = b;
      s3 = c;
      l1 = d;
      l2 = e;
      l3 = f;
    }

    @Override
    public boolean equals(Object obj) {
      brokenCounter += 1;
      return false;
    }

    @Override
    public int hashCode() {
      return 1;
    }
  }

  // Object that uses Eclipse's generated equals implementation.
  public class MyObjectPlain {
    public String s1;
    public String s2;
    public String s3;
    public Long l1;
    public Long l2;
    public Long l3;

    public MyObjectPlain(String a, String b, String c, Long d, Long e, Long f) {
      s1 = a;
      s2 = b;
      s3 = c;
      l1 = d;
      l2 = e;
      l3 = f;
    }

    @Override
    public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + getOuterType().hashCode();
      result = prime * result + ((l1 == null)
          ? 0
          : l1.hashCode());
      result = prime * result + ((l2 == null)
          ? 0
          : l2.hashCode());
      result = prime * result + ((l3 == null)
          ? 0
          : l3.hashCode());
      result = prime * result + ((s1 == null)
          ? 0
          : s1.hashCode());
      result = prime * result + ((s2 == null)
          ? 0
          : s2.hashCode());
      result = prime * result + ((s3 == null)
          ? 0
          : s3.hashCode());
      return result;
    }

    @Override
    public boolean equals(Object obj) {
      plainCounter += 1;
      if (this == obj)
        return true;
      if (obj == null)
        return false;
      if (getClass() != obj.getClass())
        return false;
      MyObjectPlain other = (MyObjectPlain) obj;
      if (!getOuterType().equals(other.getOuterType()))
        return false;
      if (l1 == null) {
        if (other.l1 != null)
          return false;
      }
      else if (!l1.equals(other.l1))
        return false;
      if (l2 == null) {
        if (other.l2 != null)
          return false;
      }
      else if (!l2.equals(other.l2))
        return false;
      if (l3 == null) {
        if (other.l3 != null)
          return false;
      }
      else if (!l3.equals(other.l3))
        return false;
      if (s1 == null) {
        if (other.s1 != null)
          return false;
      }
      else if (!s1.equals(other.s1))
        return false;
      if (s2 == null) {
        if (other.s2 != null)
          return false;
      }
      else if (!s2.equals(other.s2))
        return false;
      if (s3 == null) {
        if (other.s3 != null)
          return false;
      }
      else if (!s3.equals(other.s3))
        return false;
      return true;
    }

    private EqualsTest getOuterType() {
      return EqualsTest.this;
    }
  }
}

And here’s the output

Time taken for plain is 804ms set size is 8696 calls = 39185108
Time taken for append is 3030ms set size is 8696 calls = 39185108
Time taken for reflection is 20765ms set size is 8696 calls = 39185108
Time taken for pojomatic is 4094ms set size is 8696 calls = 39185108
Time taken for broken is 604ms set size is 10000 calls = 49995000

Given that the set size and the number of equals calls are the same, you can be reasonably sure that each implementation is as correct as the others, other than the intentionally broken one, which was meant to help illustrate this point.

The results speak for themselves. The Eclipse generated solution is fastest, followed by append, followed closely by pojomatic. Finally, the reflection based implementation took over 25x the amount of time as the fastest solution.

Older Posts »

Blog at WordPress.com.