Showing posts with label pattern. Show all posts
Showing posts with label pattern. Show all posts

Wednesday, April 2, 2014

Java frameworks, encapsulation and code bloat, i.e., the javabean specification failed us!

I have recently run into the following error in my JAX-RS application running in Jersey 2.6 (on Tomcat 6):

 Failed to generate the schema for the JAX-B elements  
 com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions  
 com.tinypass.rest.v3.framework.dto.RestDTOFromEntity does not have a no-arg default constructor.  
   this problem is related to the following location:  
    at com.tinypass.rest.v3.framework.dto.RestDTOFromEntity  
    at com.tinypass.rest.v3.dto.AppDTO  
    at com.tinypass.rest.v3.dto.AppSensitiveDTO  
   at com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:91)  
   at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:436)  
   at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.(JAXBContextImpl.java:277)  
   at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1100)  
   at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:143)  
   at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:110)  
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)  
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)  
   at java.lang.reflect.Method.invoke(Method.java:597)  
   at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:202)  
   at javax.xml.bind.ContextFinder.find(ContextFinder.java:376)  
   at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:574)  
   at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:522)  
   at org.glassfish.jersey.server.wadl.internal.generators.WadlGeneratorJAXBGrammarGenerator.buildModelAndSchemas(WadlGeneratorJAXBGrammarGenerator.java:368)  
   at org.glassfish.jersey.server.wadl.internal.generators.WadlGeneratorJAXBGrammarGenerator.createExternalGrammar(WadlGeneratorJAXBGrammarGenerator.java:317)  
   at org.glassfish.jersey.server.wadl.internal.WadlBuilder.generate(WadlBuilder.java:121)  
   at org.glassfish.jersey.server.wadl.internal.WadlApplicationContextImpl.getApplication(WadlApplicationContextImpl.java:143)  
   at org.glassfish.jersey.server.wadl.internal.WadlApplicationContextImpl.getApplication(WadlApplicationContextImpl.java:162)  
   at org.glassfish.jersey.server.wadl.processor.WadlModelProcessor$OptionsHandler.apply(WadlModelProcessor.java:138)  
   at org.glassfish.jersey.server.wadl.processor.WadlModelProcessor$OptionsHandler.apply(WadlModelProcessor.java:120)  
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)  
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)  
   at java.lang.reflect.Method.invoke(Method.java:597)  
   at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)  
   at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:151)  
   at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:171)  
   at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:152)  
   at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:104)  
   at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:406)  
   at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:350)  
   at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:106)  
   at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:259)  
   at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)  
   at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)  
   at org.glassfish.jersey.internal.Errors.process(Errors.java:315)  
   at org.glassfish.jersey.internal.Errors.process(Errors.java:297)  
   at org.glassfish.jersey.internal.Errors.process(Errors.java:267)  
   at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:319)  
   at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:236)  
   at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1028)  
   at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:373)  
   at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:381)  
   at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:344)  
   at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:219)  
   at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)  
   at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)  
   at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)  
   at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)  
   at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)  
   at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)  
   at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)  
   at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)  
   at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)  
   at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)  
   at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)  
   at java.lang.Thread.run(Thread.java:662)  


It looks like this is happening when the user tries to retrieve the application.wadl file. This error occurs because the class RestDTOFromEntity does not have a default constructor. For some reason JAXB requires this no-arg constructor to generate the WADL file. This can be fixed by adding a private no-arg constructor to RestDTOFromEntity.

The absence of a default constructor for that class is motivated by design choices made to properly encapsulate the contents of this class. It's a safe way to force programmers to provide the parameters required to the constructor (which will appropriately throw in case of nulls etc.). A non default constructor would be required if the class was immutable (which is not in this case). This and other encapsulation choices are very common in "academic" object oriented design.

In this specific example, the solution does not break the encapsulation of the class, however it does increase the code bloat with a private no-arg constructor that sits there for no apparent reason (and I believe there might be instances in which framework support requires breaking encapsulation or other OOP principles).

I feel like most Java frameworks built on the javabean specification end up running into this kind of problems. Here are some examples:
  • It's common practice in Spring to have default constructors and setters: this is terrible OOP design that leaves the object to all kinds of potential bugs; this can be fixed by using constructor injection but nobody does that because it's a feature added later and because everyone is so used to the javabean paradigm.
  • Again, in Spring, it's common practice to instantiate beans with "singleton" scope: this "singleton" is usually an instance of a class; if by accident your application starts with two application contexts, you end up with two singletons! This problem can be solved by using an actual singleton and a factory method, e.g., `getInstance()`, to register the singleton with the Spring context. The method could also take care of DI, but again, this is an even more obscure feature of Spring that nobody uses.
  • Objects serialized/deserialized using Jackson typically require a default constructor unless a constructor is defined as a JsonCreator. Once again, the javabean paradigm is so widely spread that many java programmers look at code like that and think I'm insane. Besides, the JsonCreator constructor usually looks pretty terrible and requires to define the properties name in two different places (code bloat + duplication)!
In my experience with (legacy) Java web apps, it looks like these problems are compounded by generally poor design practices, once again fostered by the javabean model: poor encapsulation and lack of immutability. This, together with layer violation in monolithic java apps (like a Spring app would be, ironically!), like using ORM objects in frontend code, leads to unmanageable and fragile code.

Some could argue that being diligent and methodical can prevent programmers from falling into bad practices. However, in my experience this also means swimming against the current because following the right path sometimes leads to horrible code bloat ("what's that giant constructor with all the properties? use setters!") in the best case scenarios and straight up bugs (as the one above) in the worst case scenarios. Taking the easy way out is then justified by the mere existence of the javabean paradigm: every class becomes mutable, with every property (be it a simple type or an object) effectively escaping encapsulation and thread safety (which is "fixed" by using heavy synchronized blocks). So in one single move, the javabean specification flushes down the toilet all the "academic" 101 design practices and makes our life so much harder in the long run.

Javabeans you have failed me!

Tuesday, August 21, 2012

Rabin-Karp Algorithm

Here's a juicy code example implementing the Rabin-Karp algorithm in java. The Rabin-Karp algorithm is a string matching algorithm: given a text and a pattern string, the algorithm will return the location(s) of the given pattern in the text. Assuming the size of the text is n characters and the size of the pattern is m characters the average and best case running time is O(n+m).
The idea is quite simple: treat the pattern p0,m-1 as if it was a number expressed in radix-d notation, i.e., of the form:
P = p0 × dm-1+p1 × dm-2 + ... + pm-1 × d0
Now, a match is found if a substring of the text represents the same exact integer, i.e., the pattern p0,m-1 matches a substring tk,k+m-1 (0 ≤ k ≤ n-m), or equivalently:
P = Tk = tk × dm-1 + tk+1 × dm-2 + ... + tk+m-1 × d0
It's easy to see that the radix-d integer for the substring starting at index location k can be easily computed from the radix-d integer for the substring starting at k-1:
Tk = tk × dm-1 + tk+1 × dm-2 + ... + tk+m-1 × d0 =
     = (tk-1 × dm-1 + tk × dm-2 + ... + tk+m-2 × d0 - tk-1 × dm-1) × d + tk+m-1 =
     = (Tk-1 - tk-1 × dm-1) × d + tk+m-1
That is, subtract the first character of the previous substring multiplied by the radix to the size of the pattern minus one, then multiply by the radix and add the last character of the new substring. It's very straightforward on paper, although it can be tricky to get right.
This approach would certainly work if we could easily store in some integer type the radix-d numbers represented by the strings. Unfortunately, this is not always the case (almost never in fact). Let's look at a simple example: assume your char size is 8 bit, so that you would naturally choose the radix 256=28, since each digit represents a value between 0 and 255=28-1. An m-char string can express numbers between 0 and 256m-1=28×m-1. If we want to store these integers in a 64 bit unsigned long type, we can only represent strings of length 8: 28×8=264. Bottom line: we can't express P and Tk using integers.
This is where the most powerful idea of the Rabin-Karp algorithm comes to play. We don't need to represent these huge numbers, but only their value modulo a big enough prime q, i.e., P mod q and Tk mod q. The catch is that if the match is positive, i.e., the hash codes are identical, we still need to check for equality between the pattern and the substring to make sure it's not a false positive. This obviously increases the computation time if there are a lot of false positives.
One last thing worth noting is that the Rabin-Karp algorithm works very well to match multiple patterns all at once: instead of storing a single key P, we can store a set of keys P1,...,l for each pattern. Great care has to be made in computing the keys Tk now since the patterns can have different lengths, but once one gets the details right, it's quite straightforward.
Follows a simple java implementation of the Rabin-Karp algorithm to find all instances of a single pattern in a text.