Erreur sur une action d'un autre Objet

Bonjour,

Le soucis suivant a été abordé dans un autre ticket mais comme il est possible que se soit un problème a part je le met dans un nouveaux ticket.

J’ai un objet NamJeune qui a la méthode suivante :

    public String openDemandeRenouvellementSoutientAvenant() {
        return javascript(
                "var b = app.getBusinessObject('NamContratAvenant', '" + NamInstanceName.AVENANT_PROLONGATION_SOUTIEN + "'); " +
                        "$ui.displayForm(null, b, app.DEFAULT_ROW_ID, {nav: 'add', parent: { name: obj.getName(), inst: obj.getInstanceName(), field: 'namCavenantJenId', rowId: obj.getRowId(), object: obj } })"
        );
    }

Cette méthode est appelé par une Action puis une fonction sur NamContratAvenant me permettant de l’afficher sous la forme de bouton dans le formulaire de création de NamJeune.

Depuis quelque temps j’ai une erreur qui ne part pas avec les reboot du serveur ou les clear cache :

2020-12-08 16:23:50,045 ERROR [com.simplicite.util.engine.ObjectManager] SIMPLICITE|http://d0e06ba9c233:8080||ERROR|designer|com.simplicite.util.engine.ObjectManager|invokeAction||Event: Method openDemandeRenouvellementSoutientAvenant not found in object NamJeune
    java.lang.NoSuchMethodException: com.simplicite.objects.name.NamCandidat.openDemandeRenouvellementSoutientAvenant(java.util.Map)
     at java.base/java.lang.Class.getMethod(Class.java:2122)
     at com.simplicite.util.engine.ObjectManager.invokeActionSync(ObjectManager.java:4282)
     at com.simplicite.util.ObjectDirect.invokeAction(ObjectDirect.java:623)
     at com.simplicite.util.ObjectDB.invokeAction(ObjectDB.java:1990)
     at com.simplicite.webapp.tools.JSONServletTool.action(JSONServletTool.java:1743)
     at com.simplicite.webapp.ObjectJson.action(ObjectJson.java:677)
     at com.simplicite.webapp.tools.JSONServletTool.businessObjectService(JSONServletTool.java:615)
     at com.simplicite.webapp.servlets.AbstractJSONServlet.service(AbstractJSONServlet.java:70)
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
     at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
     at com.simplicite.webapp.filters.AuthMethodFilter.doFilter(AuthMethodFilter.java:139)
     at com.simplicite.webapp.filters.AbstractFilter.doFilter(AbstractFilter.java:37)
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
     at com.simplicite.webapp.filters.HTTPHeadersFilter.doFilter(HTTPHeadersFilter.java:39)
     at com.simplicite.webapp.filters.AbstractFilter.doFilter(AbstractFilter.java:37)
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
     at com.simplicite.webapp.filters.RewriteFilter.doFilter(RewriteFilter.java:86)
     at com.simplicite.webapp.filters.AbstractFilter.doFilter(AbstractFilter.java:37)
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
     at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:188)
     at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
     at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
     at com.simplicite.tomcat.valves.APISessionValve.invoke(APISessionValve.java:192)
     at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
     at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
     at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
     at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
     at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
     at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
     at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
     at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
     at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)
     at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
     at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
     at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
     at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
     at java.base/java.lang.Thread.run(Thread.java:832)

Les autres utilisateurs n’ont pas le problème et si j’exporte le module sur un aurte serveur (en local) j’ai toujours la meme erreur.

Est-ce que vous auriez une solution pour me sortir de cette situation inhabituelle ?
Merci par avance.

Je ne suis pas sûr de bien comprendre ce que vous avez configuré…

Une méthode d’action doit être dans la classe de l’objet sur laquelle l’action est configurée, dans le stacktrace on voit un appel : com.simplicite.objects.name.NamCandidat.openDemandeRenouvellementSoutientAvenant(java.util.Map) donc sur l’objet NamCandidat pas sur NamJeune.

Sinon votre action semble être uniquement du JS client vous pourriez donc la configurer plutôt comme une action “front” (= UI) avec une URL du genre javascript:maFonction(...) avec la fonction en question implémentée dans la ressource SCRIPT (JS) de votre objet. Aucun intérêt à aller executer du code serveur dans ce cas là à priori. Exemple d’action front de ce type: l’action DEMO_CLIENTMAP sur l’objet DemoClient de la démo.

Tout à fait d’accord la dessus mais mon action pointe bien sur NamJeune, je ne pense pas avoir fait d’erreur , du moins je pense :



En phase, je pense qu’il faut créer la méthode openDemandeRenouvellementSoutientAvenant dans votre objet NamJeune et non pas NamContratAvenant. Mais je ne sais pas exactement quel est le besoin de qui doit porter cette action.

Si votre action est utilisée sur plusieurs fonctions dans plusieurs objets, il faut que chacun d’entre eux implémente la méthode back. Si celle-ci est identique, utilisez un héritage pour factoriser la méthode ou une classe partagée.

Si vous faites une Action front, idem le SCRIPT front doit être implémenté dans chaque objet qui utilise l’action.

Merci,
quel est le paramétrage des fonctions de votre objet NameCandidat ?
car c’est lui qui semble bien porter l’action également, sans avoir la méthode implémentée.

voila la configuration de NamCandidat :

pour le code je vous laisses regarder dans le code que l’on vous as envoyé ça sera plus simple

En regardant le code source envoyé, la méthode dans NamJeune.java s’appelle :
“openDemandeRenouvellementSoutientAvenantForm”

et non pas ce qui est paramétré sur l’Action :
“openDemandeRenouvellementSoutientAvenant”

Pouvez-vous vérifier ?

Je vais regarder la log Simplicité car elle n’est pas très clair.

oui en fait j’ai modifié le nom depuis, pareil pour le nom de l’action il a peut-etre changé par rapport a la version que vous avez recu. C’est parceque j’ai fait le test de supprimer la fonction et l’action, de changer le nom de la méthode en java, et de tout refaire en faisant des clear cache entre 2.

Ok merci. la log est également correcte.

  • Simplicité cherche bien la méthode dans l’objet NamJeune
  • Mais il y a un problème étrange car NamJeune a chargé la classe de NamCandidat

Le this.getClass() de votre objet NamJeune instancié retourne la classe com.simplicite.objects.name.NamCandidat au moment où l’action est invoquée par reflection.

On va devoir passer votre implémentation au debugger car je n’ai jamais vu ça, il y a forcement un truc louche lors du chargement de l’objet pour se “tromper” de classe.

Est-ce que par hasard l’attribut “Class” de l’un ou l’autre de vos objets est renseigné ?

Non pour les deux ( NamJeune et NamCandidat ) cet attribut est vide

Suite à installation en local de vos modules :

  • Il y avait un problème de compilation du PlatformHooks sur une 5.1 (latest). La classe PlatformHookInterface a changé de package, on a ajouté un wrapper pour compatibilité ascendante de l’implémentation. En 5.0 (beta) il n’y a normalement pas de problème à ce niveau.

  • Il y a quelques problèmes pour créer des entités avant d’arriver au “Jeune”. Il faut nécessairement une base postgreSQL sinon ça ne marche pas bien (il y a des entiers configurés en taille 100 ou 200 notamment qui tombe en erreur SQL, je ne vois pas bien le besoin d’une telle taille).

Je vais réinstaller sur base PostgreSQL et je vous tiens informé.

@Francois je suis en train d’installer une instance sur l’image Docker “5-beta” avec la version de PostgreSQL la plus proche de celle qu’ils utilisent. On sera alors au plus proche de ce qu’ils ont déployé. Je te tiens au courant quand c’est prêt

Je pense avoir trouvé, le problème semble lié au paramétrage de vos héritages.

public class NamCandidat extends NamJeuneCandidatCommon

Mais cet objet est paramétré pour hériter de NamJeune

il faudrait donc plutôt que votre classe Java suive cette logique pour forcer Simplicité à utiliser la bonne classe :

public class NamCandidat extends NamJeune

puisque NamJeune n’hérite d’aucun objet métier, juste d’une classe commune :

public class NamJeune extends NamJeuneCandidatCommon

J’ai fait la modification et plusieurs tests et cela fonctionne, merci :)

Est-ce que vous avez une idée de pourquoi ce problème apparait maintenant ?
Cette portion de code et de paramètrage n’ont pas évolués depuis pas mal de temps

Pas facile de comprendre effectivement sans tracer ce que faisait le URLClassLoader, mais je pense que ça doit être lié à l’ordre de chargement des classes. Si on utilisait Jeune ou Candidat en premier, le comportement devait être différent lors de l’instanciation en mémoire.

En héritant explicitement de la bonne classe, il ne devrait plus y avoir de doute. Vérifiez vos autres héritages.

En tout cas, on utilise souvent l’héritage d’objet (à plusieurs niveaux pour factoriser des attributs, pour segmenter des accès par rapport un statut ou un type…) et on n’avait jamais vu ce genre de comportement d’inversion de classe.

PS:

En complément cf. une de mes réponses précédentes => si votre action est purement UI il faut la configurer comme une action “front” avec une URL qui appelle du JS client (javascript:...), c’est inutile de solliciter le serveur pour retourner un simple statement statique JS qui s’exécutera in fine coté client.

Les seuls cas où il est éventuellement nécessaire d’avoir une action serveur c’est si le statement JS en question est dynamique (= dépend de choses qui n’existent ou qui ne sont accessibles que coté serveur). Dans votre cas ce n’est pas vraiment le cas.

en fait ce choix correspond au problème décrit dans ce ticket :

Le cas où une action retourne un statement JS généré dynamiquement coté serveur (return javascript(...)) est fréquent.

Dans le cas précis que vous indiquez c’est à priori du JS totalement statique que renvoie votre action (à part une constante à priori statique Java). Mais il me manque peut être des infos pour bien cerner votre cas.

En tout cas quand il s’agit de ne faire que du JS coté client il est préférable de faire une action purement front pour ne pas solliciter le serveur pour rien.

Pour mémoire, le pattern où on renvoie une URL genre HTMLTool.getFormURL(...) est un pattern legacy hérité de l’ancienne UI des version 3.x, il continue à marcher car on a fait ce qu’il faut coté client pour “traduire” à la volée ces URLs legacy en appels JS mais c’est à considérer comme “deprecated”.

Pour mémoire l’ancienne UI avait été conservée en 4.0 pour laisser le temps au clients de basculer sur la nouvelle, mais en version 5 elle a définitivement disparue, tout ce qui lui est associé finira donc par disparaitre un jour.