Configuring Package Version Information in JAR Manifests
To identify the versioning details of a package within a Java Archive (JAR), you can utilize specific headers in the MANIFEST.MF file. These headers allow you to define specifications and implementation details for your code.
| Header Name | Description |
|---|---|
Name |
The relative path of the package. |
Specification-Title |
The formal title of the package specification. |
Specification-Version |
The version number of the specification. |
Specification-Vendor |
The organization that owns the specification. |
Implementation-Title |
The title of the actual implementation/binary. |
Implementation-Version |
The specific build number or version of the binary. |
Implementation-Vendor |
The organization providing the implementation. |
Example of a manifest entry for a custom utility package:
Name: com/dev/services/
Specification-Title: Core Service API
Specification-Version: 2.1
Specification-Vendor: DevCorp Systems
Implementation-Title: com.dev.services
Implementation-Version: release-candidate-1
Implementation-Vendor: DevCorp Systems
To apply this, create a text file (e.g., pkg_info.txt) with the content above. Ensure the file ends with a blank new line to prevent parsing errors. Then, bundle it using the jar tool:
jar cfm AppPackage.jar pkg_info.txt com/dev/services/*.class
Sealing Packages in a JAR
Package sealing ensures that all classes within a specific package originate from the same JAR file. This is crucial for maintaining version consistency and security.
To seal a package, add the Sealed attribute under the package's name in the manifest:
Name: com/secure/module/
Sealed: true
To seal the entire JAR file, place the attribute in the main section of the manifest:
Manifest-Version: 1.0
Sealed: true
Enhancing Security via Manifest Attributes
Modern Java applications (especially those deployed via Java Web Start or Applets) use manifest attributes to restrict execution environments and prevent unauthorized code redistribution.
- Permissions: Defines the level of access (e.g.,
all-permissionsorsandbox). - Codebase: Restricts the JAR to be loaded only from specific domains.
- Entry-Point: Specifies which classes are allowed as execution starting points.
- Trusted-Only: Blocks the loading of untrusted components within the same environment.
Signing and Verifying JAR Files
Digital signatures allow users to verify the author of a JAR and ensure its contents haven't been tampered with. Signing requires a private key stored in a keystore.
Key Components of Signing
- Private Key: Used to create the signature.
- Public Key & Certificate: Included in the JAR to allow users to verify the signature via a Certificate Authority (CA).
- Digest: A hash of each file's content. If the file changes, the digest mismatch invalidates the signature.
Using the jarsigner Tool
The jarsigner command signs a JAR file using a key alias from your keystore:
jarsigner -keystore myStore.jks -tsa http://timestamp.digicert.com app.jar release_key
To verify the signature of an existing JAR:
jarsigner -verify -verbose app.jar
Accessing JARs Programmatically
Java provides the java.util.jar and java.net.JarURLConnection APIs to interact with archives at runtime. Below is an example of a custom class loader that reads the Main-Class attribute from a remote JAR.
public class RemoteJarLoader extends URLClassLoader {
private URL archiveUrl;
public RemoteJarLoader(URL url) {
super(new URL[] { url });
this.archiveUrl = url;
}
public String getEntryClassName() throws IOException {
URL manifestUrl = new URL("jar", "", archiveUrl + "!/");
JarURLConnection connection = (JarURLConnection) manifestUrl.openConnection();
Attributes mainAttrs = connection.getMainAttributes();
return mainAttrs != null ? mainAttrs.getValue(Attributes.Name.MAIN_CLASS) : null;
}
}
Introduction to Java Foundation Classes (Swing)
Swing is the primary API for building Graphical User Interfaces (GUIs) in Java. It is part of the JFC (Java Foundation Classes) and offers pluggable look-and-feel suppport, accessibility features, and 2D graphics.
A Minimal Swing Application
The following example creates a simple window with a "Hello World" label.
import javax.swing.*;
public class SimpleApp {
private static void initGui() {
JFrame mainFrame = new JFrame("Demo Window");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel infoLabel = new JLabel("Welcome to Swing", SwingConstants.CENTER);
mainFrame.getContentPane().add(infoLabel);
mainFrame.setSize(300, 100);
mainFrame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> initGui());
}
}
Building GUIs with NetBeans
NetBeans provides a drag-and-drop GUI Builder that generates the underlying Swing code automatically. Key panels include:
- Palette: Contains components like
JButton,JLabel, andJTextField. - Design Area: The visual canvas for arranging components.
- Inspector: A tree view of the component hierarchy.
- Properties: A panel to modify attributes like font, text, and variable names.
Example: Celsius to Fahrenheit Converter Logic
In a GUI application, you typically respond to events. Here is the logic for a conversion button:
private void onConvertClick(java.awt.event.ActionEvent evt) {
try {
double celsius = Double.parseDouble(inputField.getText());
int fahrenheit = (int) (celsius * 1.8 + 32);
resultLabel.setText(fahrenheit + " °F");
} catch (NumberFormatException e) {
resultLabel.setText("Invalid Input");
}
}
Core Swing Components and the JComponent Class
Most Swing components inherit from JComponent, which provides features like tooltips, borders, and double buffering.
- Top-Level Containers:
JFrame,JDialog, andJAppletserve as the root of the UI hierarchy. - Content Pane: The layer where visible components are added.
- Text Components: Includes
JTextField(single line),JTextArea(plain multi-line), andJTextPane(styled text).
Using DocumentFilters for Input Control
A DocumentFilter allows you to intercept and modify user input before it reaches the model. This example creates a numeric-only filter:
public class NumericFilter extends DocumentFilter {
@Override
public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr)
throws BadLocationException {
if (string.matches("\\d+")) {
super.insertString(fb, offset, string, attr);
}
}
@Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs)
throws BadLocationException {
if (text.matches("\\d+")) {
super.replace(fb, offset, length, text, attrs);
}
}
}
Managing Undo/Redo in Text Components
To implement undo and redo functionality, use an UndoManager and register it as an UndoableEditListener on the component's document.
UndoManager manager = new UndoManager();
myTextArea.getDocument().addUndoableEditListener(e -> manager.addEdit(e.getEdit()));
// To undo:
if (manager.canUndo()) {
manager.undo();
}