Java ( 10 / 36 articles - Voir la liste )

Erreur java.lang.IllegalStateException

Il arrive de rencontrer des IllegalStateException lorsqu'on effectue des redirections dans des servlets.

En général ça se produit quand on a déjà envoyé des données ou qu'on a déjà demandé une redirection dans notre requête HTTP.

Pour éviter cela, il suffit d'utiliser la méthode isCommited() en remplaçant

// ServletResponse response

if (response != null) {
 response.sendRedirect("http://www.google.fr");
 return;
}

par

// ServletResponse response

if (response != null && !response.isCommited()) {
 response.sendRedirect("http://www.google.fr");
 return;
}

Astuce Impossible de trouver mon nouveau skin dans JCMS

Je viens de créer un nouveau skin dans JCMS, mais malgré un redémarrage ou le vidage du work de tomcat, il n'apparaît pas dans la liste de choix du skin de mes portlets.

Par défaut, pour ajouter un nouveau skin il suffit de créer la jsp et de la déclarer dans le fichier plugin.xml. Par exemple :

<types>
    <templates type="AbstractPortletSkinable">
       <template name="newSkin" file="doNewSkin.jsp" usage="box">
             <label xml:lang="en">My new skin</label>
             <label xml:lang="fr">Mon nouveau skin</label>
       </template>
    </templates>
</type>

Il existe cependant un option méconnue dans le CMS : la possibilité d'activer des skins différents pour chaque espace de travail.

Pour cela :

  • Choisissez un espace de travail en back-offfice
  • Allez dans l'Espace d'administration fonctionnelle > Types de publication > Portlet
  • Éditez [Abstract] Portlet Skinable.
  • Cochez les skins à activer dans l'espace de travail

Par défaut dans JCMS, aucun n'est coché. Tous les nouveaux skins sont donc immédiatement disponibles.

Mais à partir du moment où l'un d'eux est coché, vous devrez repasser par cette interface à chaque création de skin pour l'activer manuellement.

Astuce Autoriser plusieurs soumissions de formulaire

Par mesure de sécurité, JCMS limite le nombre de soumissions des formulaires. Il faut attendre environ une minute entre chaque soumission.

Ce comportement peut-être éviter en ajoutant cette classe css sur la balise form du formulaire : noSingleSubmitButton.

Astuce Initialiser une variable de classe

Lorsqu'on utilise des variables statiques, on peut souvent les initialiser directement à leur déclaration :

public class MaClasse {

    public static String myStaticString = "Ma chaîne";
    public static String[] myStaticArray = {"Ma chaîne 1", "Ma chaîne 2"};
}

Mais si vous avez une Collection ou un autre objet en variable de classe, vous ne pourrez pas l'initialiser de cette manière.

Vous pouvez donc déclarer un bloc statique, qui sera exécuté une seule fois, à la première utilisation de la classe. Dans ce bloc, appelez une fonction statique qui se chargera d'initialiser votre variable :

public class MaClasse {

    public static List<String> myStaticList = new ArrayList<String>();

    static {
        MaClasse.initMyStaticList();
    }

    private static void initMyStaticList() {

        MaClasse.myStaticList.add("Ma chaîne 1");
        MaClasse.myStaticList.add("Ma chaîne 2");
    }
}

Astuce Ajouter un espace (ou autre) tous les n caractères

Si vous souhaitez formater un numéro de téléphone, un IBAN, ou n'importe quelle chaîne en y ajoutant régulièrement un séparateur, cette fonction peut vous être utile :

/**
 * Formate une chaîne en ajoutant un séparateur tous les <code>length</code> caractères.
 * 
 * @param string Chaîne à formater
 * @param separator Séparateur à ajouter
 * @param length Taille des groupes de caractères à séparer
 * @return La chaîne formatée
 */
public static String addChar(String string, String separator, int length) {

    if (string != null && string.length() > length) {

        string = string.replaceAll("([^\\s]{" + length + "})", "$0" + separator);
    }

    return string;
}

Astuce Afficher une erreur dans JCMS

Dans JCMS (7 et +) les erreurs sont affichées dans un bloc ressemblant à ça.

Affichage d'une erreur dans JCMS

Transmettre le message

Vous devez tout d'abord transmettre votre message à JCMS.

  • Si vous êtes dans une JSP, utilisez l'une ou l'autre de ces méthodes :
// Ajoute un message d'erreur dans la request
setErrorMsg("Le téléchargement du document a échoué", request);

// Ajoute un message d'erreur dans la session
setErrorMsgSession("Le téléchargement du document a échoué", request);
  • Pour faire la même chose dans une classe Java, utilisez l'une de celles-ci :
    // Ajoute un message d'erreur dans la request
    JcmsContext.setErrorMsg("An error occured while saving your content", request);

    // Ajoute un message d'erreur dans la session
    JcmsContext.setErrorMsgSession("An error occured while saving your content", request);

Remarque :

Des méthodes équivalentes existent pour les messages d'information et d'avertissement.

Afficher le message

Une fois le message transmis, il reste à l'afficher. Il suffit pour cela d'inclure ce bout de code :

<%@ include file='/jcore/doMessageBox.jsp' %>

Cette JSP fournie par JCMS, va récupérer tous les messages d'information, d'avertissement ou d'erreur présents en session, dans les paramètres de la request et dans le contexte de la page. Chaque message trouvé est affiché.

Remarque :

Depuis la version 7.1 JCMS utilise Bootstrap. Si vous êtes en version antérieure, le message d'erreur ne ressemblera pas à celui ci-dessus.

Astuce Ordre des champs en ExtraData

Lors de l'affichage des champs en ExtraData, JCMS utilise l'ordre l'alphabétique des clés des propriétés d'ExtraData.

Si votre plugin.prop contient les propriétés suivantes :

extra.Category.jcmsplugin.monplugin.premierchamp
extra.Category.jcmsplugin.monplugin.champ2
extra.Category.jcmsplugin.monplugin.champ3
extra.Category.jcmsplugin.monplugin.dernierchamp

Les champs s'afficheront dans cet ordre en back-office :

  • champ2
  • champ3
  • dernierchamp
  • premierchamp

Astuce Tester si une chaîne est vide ou ne contient que des espaces

Voici une méthode pour tester si une chaîne est vide ou contient uniquement des espaces :

/**
 * Retourne si la chaîne en argument est vide ou contient uniquement des espaces.
 * 
 * @param string Chaîne
 * @return <code>true</code> si la chaîne est nulle, vide, ou s'il ne contient que des caractères espaces (ex: \n \r \s, ...) y compris les espaces insécables.
 */
public static boolean isEmpty(String string) {

    boolean isEmpty = true;

    if (string != null) {

        isEmpty = "".equals(string.replaceAll("[\\s|\\u00A0]+", ""));
    }

    return isEmpty;
}

Remarque :

\u00A0 représente les espaces insécables. Si on utilise uniquement \s dans le remplacement, ils ne seront pas considérés comme des espaces.

Marque-page Un décompilateur Java dans Eclipse

L'application Java Decompiler permet de décompiler un fichier .class simple ou tous ceux présents dans un JAR.

Le site de l'application fournit un plugin Eclipse qui ne fonctionne pas avec les dernières versions (testé avec Eclipse Juno). Plusieurs fork ont été créés et ce site en propose un qui fonctionne : JDEclipse-Realign.

Pour l'installer :

  • Cliquez sur Help > Install New Software... dans le menu d'Eclipse
  • Ajoutez un nouveau site via le bouton Add...
  • Choisissez un nom (ex: JDEclipse-Realign) et cette URL : http://mchr3k-eclipse.appspot.com/
  • Cochez JavaDecompiler Eclipse Plug-in > JD-Eclipse (Realign Edition) et suivez la procédure d'installation

Une fois installé et Eclipse redémarré, vérifiez l'association des fichiers :

  • Windows > Preferences > General > Editors > File Associations
  • Pour *.class without source sélectionnez Class File Editor par défaut

Si vous ouvrez un fichier .class (via F3 ou Ctrl + clic sur le nom d'une classe) vous devriez maintenant voir la source décompilée.

Astuce Utiliser la réflexivité

Instancier un nouvel objet d'une classe

/**
 * Retourne une publication du type en paramètre en remplissant automatiquement ses champs, et après l'avoir créer dans JCMS.
 * 
 * @param clazz La classe du type de contenu souhaité
 * @return une publication du type souhaité
 */
public static <T extends Publication> T fillPublication(Class<T> clazz) {

    Publication publication = null;
    if (Util.notEmpty(clazz)) {

        try {
            publication = clazz.newInstance();

        } catch (InstantiationException e) {

            LOGGER.error("Impossible d'instancier dynamiquement un objet de la classe \"" + clazz.getSimpleName() + "\"", e);

        } catch (IllegalAccessException e) {

            LOGGER.error("Impossible d'instancier dynamiquement un objet de la classe \"" + clazz.getSimpleName() + "\"", e);
        }
    }
    return clazz.cast(publication);
}

Appeler une méthode d'une classe

Publication publication = new Article();
Class<? extends Publication> clazz;

Method method = clazz.getMethod("getName");
String name= (String) method.invoke(publication, null);

L'intérêt de ce code est d'appeler une méthode de l'objet publication sans savoir que c'est un article.

Instancier un tableau d'objets d'une classe

int size = 3;
Objet[] publicationArray = (Publication[]) java.lang.reflect.Array.newInstance(Publication.class, size);