Skip to content

Instantly share code, notes, and snippets.

@lsloan
Last active August 12, 2016 21:46
Show Gist options
  • Save lsloan/af04dc4d5522f477657628033c42a269 to your computer and use it in GitHub Desktop.
Save lsloan/af04dc4d5522f477657628033c42a269 to your computer and use it in GitHub Desktop.
A guide to using Jython for exploring the Java environment of a project managed with Maven.

Use Jython To Explore Java

When I develop with Python, I like to use its interactive interpreter to experiment with code samples quickly and in real time. It allows me to import the code I've been developing so I can test it in a controlled environment. Java doesn't include this ability outnatively, but there are a number of ways to accomplish something similar with additional software. With my preference for Python, I chose Jython to do this.

  1. Install Jython. See jython.org for details. It may be as simple as, for example, on OS X with Homebrew:
brew install jython
  1. Use Maven to set the Java classpath for Jython from the project dependencies. This allows Jython to import all of the classes the project's Java code uses. This could be set in the CLASSPATH environment variable, but that would affect other Java programs. To limit this classpath to Jython, set the JYTHONPATH environment variable instead:
JYTHONPATH=$(mvn -q dependency:build-classpath -Dmdep.outputFile=/dev/stdout); export JYTHONPATH

If the project dependencies change, this step needs to be run again. The Maven dependency plugin has features that may be used to automate this somewhat.

  1. View the value of JYTHONPATH to verify it is set correctly.
echo $JYTHONPATH
/Users/lsloan/.m2/repository/joda-time/joda-time/2.4/joda-time-2.4.jar:/Users/lsloan/.m2/repository/org/imsglobal/caliper/caliper-java/1.0.0/caliper-java-1.0.0.jar
  1. Start the Jython interactive interpreter and verify the path includes the classpath set in the previous step.
jython
Jython 2.7.0 (default:9987c746f838, Apr 29 2015, 02:25:11)
[Java HotSpot(TM) 64-Bit Server VM (Oracle Corporation)] on java1.8.0_65
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/Users/lsloan/.m2/repository/joda-time/joda-time/2.4/joda-time-2.4.jar', '/Users/lsloan/.m2/repository/org/imsglobal/caliper/caliper-java/1.0.0/caliper-java-1.0.0.jar', '/Local/Cellar/jython/2.7.0/libexec/Lib', '__classpath__', '__pyclasspath__/', '/Local/Cellar/jython/2.7.0/libexec/Lib/site-packages']
  1. Import a Java class found only in the classpath and try using it. Remember to use Java objects in a Pythonic way.
>>> from org.joda.time import DateTime
>>> dt = DateTime()
>>> dt
2016-06-29T16:40:18.006-04:00

Try using Jython's autocompletion and history features to make typing or reusing Python statements easier. At the interpreter prompt, type dt.get, then press the Tab key. Jython will display the possible completions:

dt.get(                 dt.getCenturyOfEra(     dt.getChronology(
dt.getClass(            dt.getDayOfMonth(       dt.getDayOfWeek(
dt.getDayOfYear(        dt.getEra(              dt.getHourOfDay(
dt.getMillis(           dt.getMillisOfDay(      dt.getMillisOfSecond(
dt.getMinuteOfDay(      dt.getMinuteOfHour(     dt.getMonthOfYear(
dt.getSecondOfDay(      dt.getSecondOfMinute(   dt.getWeekOfWeekyear(
dt.getWeekyear(         dt.getYear(             dt.getYearOfCentury(
dt.getYearOfEra(        dt.getZone(

Try using other methods of the DateTime object:

>>> dt.getMonthOfYear()
6
>>> dt.plusHours(2)
2016-06-29T18:40:18.006-04:00

Use the Python dir() function to get a list of valid attributes for the object. Notice the Pythonic symbols are shown along with the Java properties and methods.

>>> dir(dt)
['Property', '__class__', '__copy__', '__deepcopy__', '__delattr__', '__doc__', '__ensure_finalizer__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__subclasshook__', '__unicode__', 'afterNow', 'beforeNow', 'centuryOfEra', 'chronology', 'class', 'compareTo', 'dayOfMonth', 'dayOfWeek', 'dayOfYear', 'equalNow', 'equals', 'era', 'get', 'getCenturyOfEra', 'getChronology', 'getClass', 'getDayOfMonth', 'getDayOfWeek', 'getDayOfYear', 'getEra', 'getHourOfDay', 'getMillis', 'getMillisOfDay', 'getMillisOfSecond', 'getMinuteOfDay', 'getMinuteOfHour', 'getMonthOfYear', 'getSecondOfDay', 'getSecondOfMinute', 'getWeekOfWeekyear', 'getWeekyear', 'getYear', 'getYearOfCentury', 'getYearOfEra', 'getZone', 'hashCode', 'hourOfDay', 'isAfter', 'isAfterNow', 'isBefore', 'isBeforeNow', 'isEqual', 'isEqualNow', 'isSupported', 'millis', 'millisOfDay', 'millisOfSecond', 'minus', 'minusDays', 'minusHours', 'minusMillis', 'minusMinutes', 'minusMonths', 'minusSeconds', 'minusWeeks', 'minusYears', 'minuteOfDay', 'minuteOfHour', 'monthOfYear', 'notify', 'notifyAll', 'now', 'parse', 'plus', 'plusDays', 'plusHours', 'plusMillis', 'plusMinutes', 'plusMonths', 'plusSeconds', 'plusWeeks', 'plusYears', 'property', 'secondOfDay', 'secondOfMinute', 'toCalendar', 'toDate', 'toDateMidnight', 'toDateTime', 'toDateTimeISO', 'toGregorianCalendar', 'toInstant', 'toLocalDate', 'toLocalDateTime', 'toLocalTime', 'toMutableDateTime', 'toMutableDateTimeISO', 'toString', 'toTimeOfDay', 'toYearMonthDay', 'wait', 'weekOfWeekyear', 'weekyear', 'withCenturyOfEra', 'withChronology', 'withDate', 'withDayOfMonth', 'withDayOfWeek', 'withDayOfYear', 'withDurationAdded', 'withEarlierOffsetAtOverlap', 'withEra', 'withField', 'withFieldAdded', 'withFields', 'withHourOfDay', 'withLaterOffsetAtOverlap', 'withMillis', 'withMillisOfDay', 'withMillisOfSecond', 'withMinuteOfHour', 'withMonthOfYear', 'withPeriodAdded', 'withSecondOfMinute', 'withTime', 'withTimeAtStartOfDay', 'withWeekOfWeekyear', 'withWeekyear', 'withYear', 'withYearOfCentury', 'withYearOfEra', 'withZone', 'withZoneRetainFields', 'year', 'yearOfCentury', 'yearOfEra', 'zone']
  1. Continue exploring!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment