Michael Gantman

Greenhorn
+ Follow
since Jan 20, 2016
Merit badge: grant badges
For More
Cows and Likes
Cows
Total received
1
In last 30 days
0
Total given
0
Likes
Total received
0
Received in last 30 days
0
Total given
2
Given in last 30 days
0
Forums and Threads
Scavenger Hunt
expand Ranch Hand Scavenger Hunt
expand Greenhorn Scavenger Hunt

Recent posts by Michael Gantman

Stephan,
Obviously this is a matter of an opinion. I see your point but respectfully disagree. Trimming the white spaces is not a major modification but rather a convenience. An unintentional space at the end of any string is hard to detect and it makes it hard to understand the cause of the problem. While I would agree that excessive tolerance may harm the system (too smart of a spellcheck for instance would correct a valid person's name such as "Nati" into a "NATO" may be a case in point), too rigid rule enforcement may be harmful either. In this case, I think, tolerating trailing white spaces is closer to a "golden" middle ground. But it is of course like I said a matter of opinion. Regardless, since it was an unexpected behavior to me, I figured this note might be useful to others (whether they agree or disagree with a sentiment)
Java 7 introduced a nio (new io) package with tons of exciting features and improvements. But recently I ran into some small feature (I am reluctant to call it a bug). Class java.nio.filePaths is a convenience class that allows to convert a String (or URI) into an instance of class Path which is one of the major components of nio. Method Paths.get() does not tolerate trailing white spaces. So lets say if a value passed to the method would be "C:\\user\\temp" it will work fine. but should it become "C:\\user\\temp " (note a space at the end of the string), it will cause the exception to be thrown:

"Exception in thread "main" java.nio.file.InvalidPathException: Trailing char > at index 12: C:\user\temp"

And that was a surprise to me. In our project we read some path for a an output folder from an external configuration file that is meant for a user to configure. we use method Paths.get() to evaluate if the path exists

Files.exists(Paths.get(userProvidedPath).

So, should user make a simple typo by adding a space at the end of a path the program would crash. Obviously the simple fix of using method userProvidedPath.trim() on the String before passing it to method Paths.get() fixes the problem. But I was expecting the code that is part of java language to be tolerant to trailing white spaces for the path since paths that only differ by trailing white spaces should be considered equal. Just to note - the problem was observed on Windows. I don't know if it reproduces on Unix/Linux.
Starting from Java 5 Java language departed from WYCIWYG (What You See is What You Get) principle and introduced some new features that violated that principle. In hind sight it was well justified. Good example of some feature is "try with resources" block (introduced in java 7) that closes all closeable resources opened in the try block. So now programmers don't have to write "finally" clause with another "try-catch" within it to close the resources and catch possible exceptions there. But the downside is that people who never wrote that annoying "finally" clause may not fully understand how it works, and that was the value of WYCIWYG.

So I would like to discuss some not very obvious pitfall with Inboxing feature. Inboxing is when there is a method that accepts a primitive parameter - such as int, but the invoker of the method passes an Instance of a corresponding class - such as Integer into the method. Java compiler and a runtime will automatically convert Integer instance into primitive int and pass into the method. So the programmer doesn't have to worry about doing it. So it is transparent.

But what would happen if there is a variable of type Integer and its value is null, and such a variable is passed as a parameter into a method receiving int? Well, behind the scene the method will be called on the Integer variable to convert it to int. But since Our variable has a null value a NullPointerException will occur at the line where the method is invoked, and the control will never even be passed to the method itself. I don't think that it is very obvious and transparent behavior. And that is the price we all pay for this nice feature and for departing from WYCIWYG. But as always this a trade off situation - you get something you loose something.
Recently I needed to write a utility based on new java time package that was introduced in java 8. IMHO this package is very well designed and implemented, flexible and robust. One of the things that I needed to get is to be able to implement some functionality for duration or interval - period of time between two instants. In particular I needed to extract a number of milliseconds from instance of Duration class. In Joda package there is an Interval class that provides such functionality (method toDurationMillis()), but class Duration does not provide such method out of the box. So I wrote one. It is not a complicated method but might save some time to other fellow programmers out there. So here is the utility class. It has another method which is a wrapper for sleep() method that "swallows" the Interrupted exception. It might be useful as well.

In one of my projects I received a requirement that stated that while parsing a text file Strings denoting a date or a timestamp are expected to be in many different formats that are not known in advance, yet all of them that represent a valid date or timestamp need to be parsed properly. So the solution I came up with is to have a set of formats stored in property file, and when a String needs to be parsed the formats are read from a file and attempts to parse the String are made sequentially with each format until it is parsed successfully or until we run out of formats. The advantages of this solution are that if you discover a valid String that was not parsed successfully, all you will need to do is to add new format to your properties file and no re-compilation and re-deployment is needed. Also this way you can set your priorities: say if US date format is preferable to European one just place US formats first and only after the European ones. Also in java 8 the format strings allow for optional format sections denoted by '[]'. So several formats actually may be combined into a single one with optional sections. For example instead of

MM/dd/yyyy
MM-dd-yyyy
MM.dd.yyyy


you can just write

MM['/']['-']['.']dd['/']['-']['.']yyyy

So, below is my set of formats that I found to cover a wide range of valid date formats. This set of course does not cover ALL possible formats. For instance it does not cover an option that date includes milliseconds. But I think it is a good set to start with if you ever have such requirement. so here it is:


M[M]['/']['-']['.']d[d]['/']['-']['.']yyyy[' ']['T'][' ']h[h]:mm:ss[' ']a[' ']['('][VV][X][x][Z][z][O][')']
M[M]['/']['-']['.']d[d]['/']['-']['.']yyyy[' ']['T'][' ']H[H]:mm:ss[' ']['('][VV][X][x][Z][z][O][')']
d[d]['/']['-']['.']M[M]['/']['-']['.']yyyy[' ']['T'][' ']h[h]:mm:ss[' ']a[' ']['('][VV][X][x][Z][z][O][')']
d[d]['/']['-']['.']M[M]['/']['-']['.']yyyy[' ']['T'][' ']H[H]:mm:ss[' ']['('][VV][X][x][Z][z][O][')']
yyyy['/']['-']['.']M[M]['/']['-']['.']d[d][' ']['T'][' ']H[H]:mm:ss[.SSS][' ']['('][VV][X][x][Z][z][O][')']
yyyy['/']['-']['.']M[M]['/']['-']['.']d[d][' ']['T'][' ']h[h]:mm:ss[' ']a[' ']['('][VV][X][x][Z][z][O][')']
M[M]['/']['-']['.']yyyy['/']['-']['.']d[d][' ']['T'][' ']H[H]:mm:ss[' ']['('][VV][X][x][Z][z][O][')']
M[M]['/']['-']['.']yyyy['/']['-']['.']d[d][' ']['T'][' ']h[h]:mm:ss[' ']a[' ']['('][VV][X][x][Z][z][O][')']
d[d]['/']['-']['.']MMM['/']['-']['.']yyyy[' ']['T'][' ']H[H]:mm:ss[' ']['('][VV][X][x][Z][z][O][')']
d[d]['/']['-']['.']MMM['/']['-']['.']yy[' ']['T'][' ']H[H]:mm:ss[' ']['('][VV][X][x][Z][z][O][')']
d[d]['/']['-']['.']MMM['/']['-']['.']yyyy[' ']['T'][' ']h[h]:mm:ss[' ']a[' ']['('][VV][X][x][Z][z][O][')']
d[d]['/']['-']['.']MMM['/']['-']['.']yy[' ']['T'][' ']h[h]:mm:ss[' ']a[' ']['('][VV][X][x][Z][z][O][')']
MMM['/']['-']['.']d[d]['/']['-']['.']yyyy[' ']['T'][' ']H[H]:mm:ss[' ']['('][VV][X][x][Z][z][O][')']
MMM['/']['-']['.']d[d]['/']['-']['.']yy[' ']['T'][' ']H[H]:mm:ss[' ']['('][VV][X][x][Z][z][O][')']
MMM['/']['-']['.']d[d]['/']['-']['.']yyyy[' ']['T'][' ']h[h]:mm:ss[' ']a[' ']['('][VV][X][x][Z][z][O][')']
MMM['/']['-']['.']d[d]['/']['-']['.']yy[' ']['T'][' ']h[h]:mm:ss[' ']a[' ']['('][VV][X][x][Z][z][O][')']
Over some time in different jobs I came across a need for several utilities that I couldn't find available at the time. And I saw that I needed them several times over and over again. So I wrote my own small library that I found very useful. So I just published it as an open source java library. Here is the link

https://github.com/michaelgantman/Mgnt/releases

Also this library is available on Maven Central. Here are the Maven artifacts (the version 1.03 is the latest at the time of writing of this article but might change to check for the latest version search for artifact "MgntUtils" at http://search.maven.org/):

<dependency>
<groupId>com.github.michaelgantman</groupId>
<artifactId>MgntUtils</artifactId>
<version>1.03</version>
</dependency>

<dependency>
<groupId>com.github.michaelgantman</groupId>
<artifactId>MgntUtils</artifactId>
<version>1.03</version>
<classifier>javadoc</classifier>
</dependency>

<dependency>
<groupId>com.github.michaelgantman</groupId>
<artifactId>MgntUtils</artifactId>
<version>1.03</version>
<classifier>sources</classifier>
</dependency>

Below is just a short explanation what is there. The library comes with a nicely written (I hope) javadoc with detailed description. So here are the list of features:

Stacktrace noise filter
In my experience this feature was the most generic and useful for me. Stacktrace is a life saver when debugging or trying to figure out what went wrong in your application. However, When working with logs on the server side you can come across huge stacktrace that contains the longest useless tail of various frameworks and Application Server related packages. And somewhere in this pile there are several lines of a relevant trace and they may be in different segments separated by useless information. It becomes a nightmare to search for a relevant stuff. Here is a link that describes the same problem with real life examples (not for the fainthearted ) https://dzone.com/articles/filtering-stack-trace-hell. So In my library There is class is called TextUtils and it has method getStacktrace() with several overridden signatures. It takes a Throwable instance and allows to set a package prefix of the packages that are relevant. Let's say your company's code always resides in packages that start with "com.plain.*" So you set such a prefix and do this



this will filter out very smartly all the useless parts of the trace leaving you with very concise stacktrace. Also I found it very convinient to pre-set the prefix and then just use the convinience method


It will do the same. To preset the prefix just use method



Also if you use Spring environment you can add the following segment to your Spring configuration and then you all set:

<beanclass=
"org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="com.mgnt.utils.TextUtils"/>
<property name="targetMethod" value="setRelevantPackage"/>
<property name="arguments" value="com.plain."/>
</bean>


Javadoc explains everything in detail. But here is a little teaser: you will get a following stacktrace:

at com.plain.BookService.listBooks()
at com.plain.BookService$$FastClassByCGLIB$$e7645040.invoke()
at net.sf.cglib.proxy.MethodProxy.invoke()
...
at com.plain.LoggingAspect.logging()
at sun.reflect.NativeMethodAccessorImpl.invoke0()
...
at com.plain.BookService$$EnhancerByCGLIB$$7cb147e4.listBooks()
at com.plain.web.BookController.listBooks()


instead of

at com.plain.BookService.listBooks()
at com.plain.BookService$$FastClassByCGLIB$$e7645040.invoke()
at net.sf.cglib.proxy.MethodProxy.invoke()
at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint()
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed()
at com.plain.LoggingAspect.logging()
at sun.reflect.NativeMethodAccessorImpl.invoke0()
at sun.reflect.NativeMethodAccessorImpl.invoke()
at sun.reflect.DelegatingMethodAccessorImpl.invoke()
at java.lang.reflect.Method.invoke()
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs()
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod()
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke()
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()
at org.springframework.aop.interceptor.AbstractTraceInterceptor.invoke()
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke()
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke()
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept()
at com.plain.BookService$$EnhancerByCGLIB$$7cb147e4.listBooks()
at com.plain.web.BookController.listBooks()


Silent String parsing into Integer, Long etc
The same class TextUtils provides methods to parse String silently (without exception ever being thrown) into types of Double, Long, Integer, Short and Byte. The methods are called parseStringToLong() parseStringToInteger() etc. They all take 4 arguments:

  • A String to be parsed
    An implementation of Number (Double, Long, Integer, Short or Byte) to serve as default value if any parsing occurred
    A String to be printed as an error message into log if the first argument is null (may be null, and then no error is printed)
    A String to be printed as an error message if NumberFormatException occurred (may be null, and then no error is printed)


  • Compare Versions
    This utility allows to convert String to version and vise-versa and to compare versions and version ranges properly. Often if you need to compare versions you just compare Strings. So lets say version "1.5.3" will be greater then version "1.3.1". However if you will compare Strings "1.4.2" and "1.12.3" the String "1.4.2" will erroneously be greater. So this Utility takes care of such problem and in addition introduces VersionRange class and allows operations on version ranges. (See methods compareVersions in class TextUtils and class VersionRange)

    String Unicode converter
    Class StringUnicodeEncoderDecoder has methods that can convert a String (in any language) into a sequence of Unicode characters and vise-versa. For example a String "Hello World" will be converted into

    "\u0048\u0065\u006c\u006c\u006f\u0020
    \u0057\u006f\u0072\u006c\u0064"

    and may be restored back.

    Web Utils
    Class WebUtils provides a method to read a binary information from http request. This method may be useful in particular if a client is uploading a large size of binary information and the server side reading is faster then client writing. This Utility allows server to throttle down and adjust server to client speed. Also may be convenient to read a client input as byte array in one go.

    File Utils
    This utility allows to read file as a String with or without specifying character set or just read it as byte array. This utility uses nio package and Buffers for faster performance. Max file size for this Utility is 2G.

    Time Util
    This is just a single convenience method that provides the same functionality as Thread.sleep() but it is silient. I.e. it "swallows" IterruptedException. Also it takes 2 arguments: time to sleep and measurement unit. So instead of



    You can just write:





    I thought it was cute

    So this is it. Feel free to download this library. It comes with MIT licence - one of the most permissive licences I know of. Source code, Javadoc and binary version is available at the link above. The code was compiled by jdk 8 but has no features of version 8 in it. It should work with java 7 most definitely, I suspect it will work with java 6 and even 5, but haven't tested it with those versions. Feel free to use it as you see fit, tell others about it if you like it and feel free to drop me a note at michael_gantman@yahoo.com if you have any feedback.