Jar modification question

M

Martin Gregorie

I need to be able to replace a default resource file with a site-specific
one. Currently I'm doing the job with a bash script that builds the
replacement resource file and then runs jar in update mode to put the new
resource into the jarfile.

This works and works well, but isn't particularly portable, so I looked
into writing a Java utility, but the java.util.jar and/or java.util.zip
packages don't seem to be able to replace files in an existing jar file.

I've thought of a few other approaches using portable scripting tools:
- Python: but not all machines have it installed
- Perl: same problem and the install is even bigger than Python
- Jython: the jars etc. are large and installation not so simple
on some systems

If I have to use any of these I'll recode the bash script in Python
because that looks to be a relatively simple install on, say, Windows.

What else would work?
 
J

John B. Matthews

Martin Gregorie said:
I need to be able to replace a default resource file with a
site-specific one. Currently I'm doing the job with a bash script
that builds the replacement resource file and then runs jar in update
mode to put the new resource into the jarfile.

This works and works well, but isn't particularly portable, so I
looked into writing a Java utility, but the java.util.jar and/or
java.util.zip packages don't seem to be able to replace files in an
existing jar file.

I've thought of a few other approaches using portable scripting tools:
- Python: but not all machines have it installed
- Perl: same problem and the install is even bigger than Python
- Jython: the jars etc. are large and installation not so simple
on some systems

If I have to use any of these I'll recode the bash script in Python
because that looks to be a relatively simple install on, say,
Windows.

What else would work?

Could you invoke `jar u...` via exec() or ProcessBuilder?

<http://download.oracle.com/javase/6/docs/technotes/tools/windows/jar.html>
 
M

Martin Gregorie

Could you invoke `jar u...` via exec() or ProcessBuilder?

<http://download.oracle.com/javase/6/docs/technotes/tools/windows/
jar.html>

I'd considered that but when I posted that I was wondering if there was
anything, such as an expanded java.util.jar package, available that would
provide a built-in solution. This morning I bit the bullet and did what
you suggested, but used Runtime.exec() rather than ProcessBuilder because
the requirement is very simple with no need to change any environment
variables or the working directory.

Its working well. I haven't had any problems with access conflicts
despite launching the program from the jar file that is being modified.
When I was researching 3rd party packages I'd seen a comment that this
wasn't a problem provided that all needed classes have been loaded from
the jar file before you start modifying it. That seems to be true.

Now I've got this running, I see that jar is not part of the standard
JRE. Is there any reason I couldn't use zip instead? I know I can quickly
try it with the Linux zip and the arguments are even similar:

zip -u MailArchive.jar ma/mailarchive.conf

instead of

jar -uvf MailArchive.jar ma/mailarchive.conf

but what I can't remember is if the first command would also work with a
Windows zip binary or even if there is a version called zip.exe that
implements the -u option.

Just in case that wouldn't work, does anybody know what the legal
position would be on distributing a copy of 'jar' with my code or if it
runs outside the SDK environment?
 
M

Mike Schilling

Martin Gregorie said:
jar.html>

I'd considered that but when I posted that I was wondering if there was
anything, such as an expanded java.util.jar package, available that would
provide a built-in solution. This morning I bit the bullet and did what
you suggested, but used Runtime.exec() rather than ProcessBuilder because
the requirement is very simple with no need to change any environment
variables or the working directory.

Its working well. I haven't had any problems with access conflicts
despite launching the program from the jar file that is being modified.
When I was researching 3rd party packages I'd seen a comment that this
wasn't a problem provided that all needed classes have been loaded from
the jar file before you start modifying it. That seems to be true.

Now I've got this running, I see that jar is not part of the standard
JRE. Is there any reason I couldn't use zip instead? I know I can quickly
try it with the Linux zip and the arguments are even similar:

zip -u MailArchive.jar ma/mailarchive.conf

instead of

jar -uvf MailArchive.jar ma/mailarchive.conf

but what I can't remember is if the first command would also work with a
Windows zip binary or even if there is a version called zip.exe that
implements the -u option.

Windows doesn’t come with a zip utility. The most commonly used one,
WinZip, needs to be purchased. The Windows Explorer can display zip files
(including jars) as if they were directories, but that doesn't help you.

The reason that java.util.jar can't replace a file within a jar is that no
one can: zip is a stream format that needs to be written from beginning to
end. What jar uf does is create a new jar with changed contents and replace
the original jar with it. The most portable solution for you is to do the
same. Or find open source code that does this; I'd be surprised if you can't
find some.
 
E

Eric Sosman

Martin Gregorie said:
[...]
but what I can't remember is if the first command would also work with a
Windows zip binary or even if there is a version called zip.exe that
implements the -u option.

Windows doesn’t come with a zip utility. The most commonly used one,
WinZip, needs to be purchased. The Windows Explorer can display zip
files (including jars) as if they were directories, but that doesn't
help you.

Perhaps they've abandoned it in newer Windows versions, but if
you've got access to an XP system try this: Right-click a folder,
pick "Send To ->" on the menu, and pick "Compressed (zipped) Folder"
on the sub-menu (the text in non-American locales may vary). You
might be surprised at what happens ...
The reason that java.util.jar can't replace a file within a jar is that
no one can: zip is a stream format that needs to be written from
beginning to end. What jar uf does is create a new jar with changed
contents and replace the original jar with it. The most portable
solution for you is to do the same. Or find open source code that does
this; I'd be surprised if you can't find some.

At least some ZIP utilities for small systems could "replace" an
archive member by writing the new version and a new central directory
at the end of the stream. This tended to vitiate the compression a
bit (because the archive now carries both versions of the member), but
was sometimes a win on slow systems with small file systems.
 
M

Martin Gregorie

This works with the Linux/UNIX zip utility. I modified my program to run
either the 'jar -uvf MailArchive.jar ma/mailarchive.conf' command or the
above zip command. That runs successfully and programs run from the
modified jar file can find and read the replaced resource.
Windows doesn’t come with a zip utility. The most commonly used one,
WinZip, needs to be purchased. The Windows Explorer can display zip
files (including jars) as if they were directories, but that doesn't
help you.
Yes, I know that: I used to use Windows, but IIRC Winzip is a GUI tool,
not something that can be used from a command line. There are command
line flavours of pkzip too, but for convenience what I really need is a
Windows port of the open source zip/unzip package used by Linux. It turns
out that this is the Info-zip package, so I should be able to compile
that myself with the djgpp port of the GNU C compiler. Problem solved.
The reason that java.util.jar can't replace a file within a jar is that
no one can: zip is a stream format that needs to be written from
beginning to end. What jar uf does is create a new jar with changed
contents and replace the original jar with it. The most portable
solution for you is to do the same. Or find open source code that does
this; I'd be surprised if you can't find some.
Yes, I did see a rather ugly looking class that uses the java.util.jar
package to copy the whole jarfile and replace the file of choice. I'll
try to find that again for future reference: meanwhile it looks as though
porting Info-zip will do the trick.
 
L

Lew

Martin said:
Yes, I know that: I used to use Windows, but IIRC Winzip is a GUI tool,
not something that can be used from a command line. There are command
line flavours of pkzip too, but for convenience what I really need is a
Windows port of the open source zip/unzip package used by Linux. It turns
out that this is the Info-zip package, so I should be able to compile
that myself with the djgpp port of the GNU C compiler. Problem solved.

http://www.cygwin.com/

I use "zip" and "unzip" from the command line on Windows all the time. I keep
"%CYGWIN_HOME%\bin" in the PATH, too.
 
R

Roedy Green

This works and works well, but isn't particularly portable, so I looked
into writing a Java utility, but the java.util.jar and/or java.util.zip
packages don't seem to be able to replace files in an existing jar file.


See http://mindprod.com/jgloss/zip.html There are two sets of
methods, for sequential and one for random. I am pretty sure you can
replace, if not, delete then add.

If that fails, look into TrueZip.
See http://mindprod.com/jgloss/truezip.html

Another possibly approach would be to look what you can do with ANT.
see http://mindprod.com/jgloss/ant.html
 
O

Owen Jacobson

I need to be able to replace a default resource file with a site-specific
one. Currently I'm doing the job with a bash script that builds the
replacement resource file and then runs jar in update mode to put the new
resource into the jarfile.

This works and works well, but isn't particularly portable, so I looked
into writing a Java utility, but the java.util.jar and/or java.util.zip
packages don't seem to be able to replace files in an existing jar file.

I've thought of a few other approaches using portable scripting tools:
- Python: but not all machines have it installed
- Perl: same problem and the install is even bigger than Python
- Jython: the jars etc. are large and installation not so simple
on some systems

If I have to use any of these I'll recode the bash script in Python
because that looks to be a relatively simple install on, say, Windows.

What else would work?

Do you need to modify the JAR? I can think of at least two approaches
that would let you override a packed-in resource with a user-defined
one:

1. Put your resource in a JAR at the same relative path
(com/example/MyResource.txt, for example) and put your JAR before the
JAR whose resources you're replacing in the class path. Normally I'd
advise against relying on ordering quirks, but this is one of the times
where it's useful.

In an EE environment, this is a little trickier to pull off, since the
JAR loading order is hugely more complex and also container-specific,
but you can take advantage of certain spec-defined behaviours: for
example, WEB-INF/classes/com/example/MyResource.txt will be loaded
instead of WEB-INF/lib/foo.jar:com/example/MyResource.txt.

2. If you control the JAR you're trying to replace resources in, then
there are some metadata-based approaches you can use. For example, you
can use SPI to implement resource providers, and treat the baked-in
implementation as the implementation of last resort fairly easily.
Alternately, add some support for a System property or configuration
entry to allow the user to specify a replacement resource path.

I'm leery of anyone who says "I need to modify my binaries". There are
usually better ways to solve the root need.

-o
 
M

Martin Gregorie

M

Martin Gregorie

Do you need to modify the JAR? I can think of at least two approaches
that would let you override a packed-in resource with a user-defined
one:
Yes, I think so. This way an outfit using the server can update the
configuration resource in the jar and then spread that round to office
machines that need the client components. This way its only one file to
distribute and no installer needed.
In an EE environment,
This is a pure SE environment.
I'm leery of anyone who says "I need to modify my binaries". There are
usually better ways to solve the root need.
I'm not modifying binaries, only replacing one text file containing
configuration details.
 
D

David

I need to be able to replace a default resource file with a site-specific
one. Currently I'm doing the job with a bash script that builds the
replacement resource file and then runs jar in update mode to put the new
resource into the jarfile.

This works and works well, but isn't particularly portable, so I looked
into writing a Java utility, but the java.util.jar and/or java.util.zip
packages don't seem to be able to replace files in an existing jar file.

I've thought of a few other approaches using portable scripting tools:
- Python: but not all machines have it installed
- Perl:   same problem and the install is even bigger than Python
- Jython: the jars etc. are large and installation not so simple
          on some systems

If I have to use any of these I'll recode the bash script in Python
because that looks to be a relatively simple install on, say, Windows.

What else would work?

There is an API with 7zip that you can use:
http://www.7-zip.org/links.html
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top