Search This Blog

Wednesday, December 13, 2017

Jython: Using dir() to find Java classes

Today's post is on how to use the dir() function to see what classes and methods are in a Java package.

The dir() function is a very powerful tool you can use to find out information about a Java package. I will demonstrate some useful hints to help you.

When working with Java, you had to use the Reflection class to find out what classes and methods were available. In Jython, it is a lot easier.

For my system, my Java packages are stored in the /usr/share/java/ folder. I use Ubuntu 16.04. So I picked the following package to work with: /usr/share/java/bcprov.jar. Any jar file will work if you don't have this particular package.

First, I took a quick peek at the jar file list, by typing (in a terminal): jar -tf /usr/share/java/bcprov.jar. jar is the app that willunpack a jar file. The -tf switch retrieves a list of files in the named package. So, my output was:

org/
org/bouncycastle/
org/bouncycastle/LICENSE.class
org/bouncycastle/apache/
org/bouncycastle/apache/bzip2/
org/bouncycastle/apache/bzip2/BZip2Constants.class
org/bouncycastle/apache/bzip2/CBZip2InputStream.class
org/bouncycastle/apache/bzip2/CBZip2OutputStream$1.class
org/bouncycastle/apache/bzip2/CBZip2OutputStream$StackElem.class
org/bouncycastle/apache/bzip2/CBZip2OutputStream.class
org/bouncycastle/apache/bzip2/CRC.class
org/bouncycastle/asn1/
org/bouncycastle/asn1/A
--------The rest omitted for space----------

As you see, this jar file contains a lot of classes and methods. It would take forever to go through and find what you want. The dir() built-in really comes in handy, as we'll see later.

Now that I know the top two levels of the package list, I can now open up my Jython interactive environment (for immediate results).

You must specify the filename along with the path, or it will not import. So, I entered this:

>>> import sys
>>> sys.path.append('/usr/share/java/bcprov.jar')


I'm ready to start importing the jar package. I start off with import org.bouncycastle. Then I type dir(org.bouncycastle), and I get:

>>> import org.bouncycastle
>>> dir(org.bouncycastle)
['LICENSE', '__name__', 'asn1', 'cert', 'cmc', 'cms', 'crypto', 'dvcs', 'eac', 'est', 'i18n', 'iana', 'jcajce', 'jce', 'math', 'mozilla', 'openssl', 'operator', 'pkcs', 'pkix', 'pqc', 'tsp', 'util', 'voms', 'x509']

You probably noticed that this list displayed above did not show the apache (we saw this in the partial file list shown earlier. That's okay. You can import specifically by typing import org.bouncycastle.apache. But let's do the math package. So, we would type import org.bouncycastle.math as math.

The AS keyword allows you to assign an alias to the item you just importedSp., . So, instead of tying 'org.bouncycastle (and so on), now you can do type dir(math) and see a list.

>>> import org.bouncycastle.math as math
>>> dir(math)
['Primes', '__name__', 'ec', 'field', 'raw']

You see four things under the .math sib[aclage. The names in lower case are other subpackages. You still need to type the qualified package tree to import. One way you can type it is: 'from org.bouncycastle.math import ec as ec' (without the quotes). What this really does is that it imports only ec whithout importing everything else. This will save on memory.

You notice Primes is capitalized. This is a class. Methods start with a lower case with the next word capitalized. You can import Primes the way we've been doing it, or you can assign it to a name, like this:

>>> primes = math.Primes

What would have happened if I called it with a parentheses, as if I'm instantiating a class?

>>> primes = math.Primes()
Traceback (most recent call last):
  File "", line 1, in
TypeError: can't instantiate abstract class (org.bouncycastle.math.Primes)


You would get either the above message, or one that says no constructor is set for that class. If you attempt to call a class with a () pair and you get this error, just try again without the () pair. Then what can you do?

>>> primes = math.Primes
>>> dir(primes)
['MROutput', 'SMALL_FACTOR_LIMIT', 'STOutput', '__class__', '__copy__', '__deepcopy__', '__delattr__', '__doc__', '__ensure_finalizer__', '__eq__', '__format__', '__getattribute__', '__hash__', '__init__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__subclasshook__', '__unicode__', 'class', 'enhancedMRProbablePrimeTest', 'equals', 'generateSTRandomPrime', 'getClass', 'hasAnySmallFactors', 'hashCode', 'isMRProbablePrime', 'isMRProbablePrimeToBase', 'notify', 'notifyAll', 'toString', 'wait']


You see all the attributes that are available to Primes. Now, you're getting somewhere! Of course, you may know that the attributes in ALL CAPS are constants.

>>> primes.SMALL_FACTOR_LIMIT
211


Methods, which require parentheses and sometimes 1 or more arguments. That can be researched later, when you review the Java documentation.

But, what if you do a dir() command and it returns a lot of information. What then? This is where list comprehension and indexing really come in handy.

Here I imported the math.ec sub-package:

>>> from org.bouncycastle.math import ec as ec
>>> dir(ec)
['AbstractECMultiplier', 'DoubleAddMultiplier', 'ECAlgorithms', 'ECConstants', 'ECCurve', 'ECFieldElement', 'ECMultiplier', 'ECPoint', 'ECPointMap', 'FixedPointCombMultiplier', 'FixedPointPreCompInfo', 'FixedPointUtil', 'GLVMultiplier', 'MixedNafR2LMultiplier', 'MontgomeryLadderMultiplier', 'NafL2RMultiplier', 'NafR2LMultiplier', 'PreCompInfo', 'ReferenceMultiplier', 'ScaleXPointMap', 'ScaleYPointMap', 'WNafL2RMultiplier', 'WNafPreCompInfo', 'WNafUtil', 'WTauNafMultiplier', 'WTauNafPreCompInfo', 'ZSignedDigitL2RMultiplier', 'ZSignedDigitR2LMultiplier', '__name__', 'custom', 'endo', 'tools']



I can type len(dir(ec) to see how many elements are in the list.

Say I only want to see items starting with 'M'. Here's list comprehension at work:


>>> [x for x in dir(ec) if x.startswith('M')]
['MixedNafR2LMultiplier', 'MontgomeryLadderMultiplier']

You can also index the dir(ec) list:

>>> dir(ec)[4]
'ECCurve'

What if you only want to see the first 10 items from the dir(ec) list? Slicing does the trick:

>>> dir (ec)[0:10]
['AbstractECMultiplier', 'DoubleAddMultiplier', 'ECAlgorithms', 'ECConstants', 'ECCurve', 'ECFieldElement', 'ECMultiplier', 'ECPoint', 'ECPointMap', 'FixedPointCombMultiplier']

So, now you know how the dir() function can help you in finding a class or wmethod within a jar package.

As I continue my journey of learning Jython/Python, I will be sharing what I've learned along the way. I really enjoy this language and its simplicity and powerful abilities. I hope you will too.

Until later, happy coding!

No comments:

Post a Comment