¿Por qué aparece "Excepción; debe detectarse o declararse lanzada" cuando intento compilar mi código Java?
Considerar:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;
import java.io.*;
public class EncryptURL extends JApplet implements ActionListener {
Container content;
JTextField userName = new JTextField();
JTextField firstName = new JTextField();
JTextField lastName = new JTextField();
JTextField email = new JTextField();
JTextField phone = new JTextField();
JTextField heartbeatID = new JTextField();
JTextField regionCode = new JTextField();
JTextField retRegionCode = new JTextField();
JTextField encryptedTextField = new JTextField();
JPanel finishPanel = new JPanel();
public void init() {
//setTitle("Book - E Project");
setSize(800, 600);
content = getContentPane();
content.setBackground(Color.yellow);
content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
JButton submit = new JButton("Submit");
content.add(new JLabel("User Name"));
content.add(userName);
content.add(new JLabel("First Name"));
content.add(firstName);
content.add(new JLabel("Last Name"));
content.add(lastName);
content.add(new JLabel("Email"));
content.add(email);
content.add(new JLabel("Phone"));
content.add(phone);
content.add(new JLabel("HeartBeatID"));
content.add(heartbeatID);
content.add(new JLabel("Region Code"));
content.add(regionCode);
content.add(new JLabel("RetRegionCode"));
content.add(retRegionCode);
content.add(submit);
submit.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand() == "Submit"){
String subUserName = userName.getText();
String subFName = firstName.getText();
String subLName = lastName.getText();
String subEmail = email.getText();
String subPhone = phone.getText();
String subHeartbeatID = heartbeatID.getText();
String subRegionCode = regionCode.getText();
String subRetRegionCode = retRegionCode.getText();
String concatURL =
"user=" + subUserName + "&f=" + subFName +
"&l=" + subLName + "&em=" + subEmail +
"&p=" + subPhone + "&h=" + subHeartbeatID +
"&re=" + subRegionCode + "&ret=" + subRetRegionCode;
concatURL = padString(concatURL, ' ', 16);
byte[] encrypted = encrypt(concatURL);
String encryptedString = bytesToHex(encrypted);
content.removeAll();
content.add(new JLabel("Concatenated User Input -->" + concatURL));
content.add(encryptedTextField);
setContentPane(content);
}
}
public static byte[] encrypt(String toEncrypt) throws Exception{
try{
String plaintext = toEncrypt;
String key = "01234567890abcde";
String iv = "fedcba9876543210";
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
byte[] encrypted = cipher.doFinal(toEncrypt.getBytes());
return encrypted;
}
catch(Exception e){
}
}
public static byte[] decrypt(byte[] toDecrypt) throws Exception{
String key = "01234567890abcde";
String iv = "fedcba9876543210";
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
byte[] decrypted = cipher.doFinal(toDecrypt);
return decrypted;
}
public static String bytesToHex(byte[] data) {
if (data == null)
{
return null;
}
else
{
int len = data.length;
String str = "";
for (int i=0; i<len; i++)
{
if ((data[i]&0xFF) < 16)
str = str + "0" + java.lang.Integer.toHexString(data[i]&0xFF);
else
str = str + java.lang.Integer.toHexString(data[i]&0xFF);
}
return str;
}
}
public static String padString(String source, char paddingChar, int size)
{
int padLength = size-source.length() % size;
for (int i = 0; i < padLength; i++) {
source += paddingChar;
}
return source;
}
}
Recibo una excepción no informada:
java.lang.Exception; must be caught or declared to be thrown
byte[] encrypted = encrypt(concatURL);
Así como también:
.java:109: missing return statement
¿Cómo soluciono estos problemas?
Todos tus problemas derivan de esto.
byte[] encrypted = cipher.doFinal(toEncrypt.getBytes());
return encrypted;
Los cuales están encerrados en un bloque try, catch, el problema es que en caso de que el programa encuentre una excepción no devuelve nada. Póngalo así (modifíquelo según la lógica de su programa):
public static byte[] encrypt(String toEncrypt) throws Exception{
try{
String plaintext = toEncrypt;
String key = "01234567890abcde";
String iv = "fedcba9876543210";
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE,keyspec,ivspec);
byte[] encrypted = cipher.doFinal(toEncrypt.getBytes());
return encrypted;
} catch(Exception e){
return null; // Always must return something
}
}
Para el segundo, debe detectar la excepción de la llamada al método de cifrado , así (también modifíquela según la lógica de su programa):
public void actionPerformed(ActionEvent e)
.
.
.
try {
byte[] encrypted = encrypt(concatURL);
String encryptedString = bytesToHex(encrypted);
content.removeAll();
content.add(new JLabel("Concatenated User Input -->" + concatURL));
content.add(encryptedTextField);
setContentPane(content);
} catch (Exception exc) {
// TODO: handle exception
}
}
Las lecciones que debes aprender de esto:
- Un método con un tipo de retorno siempre debe devolver un objeto de ese tipo, es decir, en todos los escenarios posibles.
- Todas las excepciones marcadas siempre deben manejarse
El problema está en este método:
public static byte[] encrypt(String toEncrypt) throws Exception{
Esta es la firma del método que más o menos dice:
- cuál es el nombre del método: cifrar
- qué parámetro recibe: una cadena llamada toEncrypt
- su modificador de acceso: público estático
- y si puede o no generar una excepción cuando se invoca.
En este caso, la firma del método dice que cuando se invoca este método "podría" generar una excepción de tipo "Excepción".
....
concatURL = padString(concatURL, ' ', 16);
byte[] encrypted = encrypt(concatURL); <-- HERE!!!!!
String encryptedString = bytesToHex(encrypted);
content.removeAll();
......
Entonces, los compiladores dicen: O lo rodeas con una construcción try/catch o declaras el método (dónde se está utilizando) para lanzar una "Excepción" por sí misma.
El verdadero problema es la definición del método "cifrar". Ningún método debería devolver nunca "Excepción", porque es demasiado genérico y puede ocultar otros tipos de excepción. Es mejor tener una excepción específica.
Prueba esto:
public static byte[] encrypt(String toEncrypt) {
try{
String plaintext = toEncrypt;
String key = "01234567890abcde";
String iv = "fedcba9876543210";
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE,keyspec,ivspec);
byte[] encrypted = cipher.doFinal(toEncrypt.getBytes());
return encrypted;
} catch ( NoSuchAlgorithmException nsae ) {
// What can you do if the algorithm doesn't exists??
// this usually won't happen because you would test
// your code before shipping.
// So in this case is ok to transform to another kind
throw new IllegalStateException( nsae );
} catch ( NoSuchPaddingException nspe ) {
// What can you do when there is no such padding ( whatever that means ) ??
// I guess not much, in either case you won't be able to encrypt the given string
throw new IllegalStateException( nsae );
}
// line 109 won't say it needs a return anymore.
}
Básicamente, en este caso particular debes asegurarte de que el paquete de criptografía esté disponible en el sistema.
Java necesita una extensión para el paquete de criptografía, por lo que las excepciones se declaran como excepciones "comprobadas". Para que usted pueda manejarlos cuando no estén presentes.
En este pequeño programa no puedes hacer nada si el paquete de criptografía no está disponible, por lo que lo verificas en el momento del "desarrollo". Si esas excepciones se producen cuando su programa se está ejecutando es porque hizo algo mal en "desarrollo", por lo que una subclase RuntimeException es más apropiada.
La última línea ya no necesita una declaración de devolución; en la primera versión detectabas la excepción y no hacías nada al respecto, eso está mal.
try {
// risky code ...
} catch( Exception e ) {
// a bomb has just exploited
// you should NOT ignore it
}
// The code continues here, but what should it do???
Si el código va a fallar, es mejor fallar rápido
Aquí hay algunas respuestas relacionadas:
Detectar excepciones en Java
Cuándo elegir excepciones marcadas y no marcadas
¿Por qué no tiene que declarar explícitamente que podría generar algunas excepciones integradas en Java?
Excepción distinta de RuntimeException