
Andrew Hanna

Andrew Hanna

Nous allons couvrir plusieurs sujets pour vous simplifier la vie, que vous utilisiez déjà les managed packages de deuxième génération ou que ce sujet soit nouveau pour vous.
Chaque nouvelle release peut demander beaucoup de temps et d’efforts. Et lorsqu’elle échoue, elle ne fournit pas toujours des erreurs assez utiles pour résoudre le problème. J’aimerais vraiment que les messages soient plus détaillés, comme avec la commande sfdx deploy. Et ce n’est pas encore la partie la plus difficile : cela devient encore plus délicat lorsque votre package est déjà créé et prêt à l’emploi, mais qu’en l’installant dans votre org de test, vous découvrez que beaucoup de fonctionnalités ne marchent pas comme prévu.
Si vous voulez éviter ce désordre ou si vous y faites déjà face, vous êtes au bon endroit pour apprendre de nos défis et erreurs, et vous épargner des maux de tête inutiles.
Commençons par comprendre les différents modificateurs d’accès dans les classes Apex afin de choisir comment implémenter votre code :
Ce modificateur d’accès est la valeur par défaut. Il signifie que la méthode ou variable est accessible uniquement dans la classe Apex où elle est définie. Si vous ne spécifiez pas de modificateur d’accès, la méthode ou variable est private.
Cela signifie que la méthode ou variable est visible par toutes les classes internes de la classe Apex qui la définit, ainsi que par les classes qui l’étendent. Vous ne pouvez utiliser ce modificateur que pour les méthodes d’instance et les variables membres. Ce réglage est strictement plus permissif que le réglage par défaut private, comme en Java.
Cela signifie que la méthode ou variable est accessible par tout Apex dans un package spécifique.
Dans Apex, le modificateur public n’a pas la même portée qu’en Java. Ce choix évite de coupler les applications entre elles et garde le code de chaque application séparé. Dans Apex, si vous voulez rendre quelque chose public comme en Java, vous devez utiliser le modificateur global.
Pour rendre un élément accessible à tous les managed packages de deuxième génération (2GP) qui partagent un namespace, utilisez public avec l’annotation @NamespaceAccessible. Dans les packages sans namespace, l’utilisation du modificateur public rend implicitement le code Apex @NamespaceAccessible.
Cela signifie que la méthode ou variable peut être utilisée par tout code Apex ayant accès à la classe, et pas seulement par le code Apex dans la même application. Ce modificateur doit être utilisé pour toute méthode qui doit être référencée en dehors de l’application, dans SOAP API ou par un autre code Apex. Si vous déclarez une méthode ou variable comme global, vous devez aussi déclarer global la classe qui la contient.
Nous recommandons d’utiliser le modificateur global rarement, voire pas du tout. Les dépendances entre applications sont difficiles à maintenir.
L’annotation @AuraEnabled permet un accès côté client et côté serveur à une méthode de contrôleur Apex. En ajoutant cette annotation, vos méthodes deviennent disponibles pour vos composants Lightning, qu’il s’agisse de Lightning web components ou de composants Aura. Seules les méthodes avec cette annotation sont exposées.
En API version 44.0 et suivantes, vous pouvez améliorer les performances runtime en mettant en cache les résultats de méthode côté client avec l’annotation @AuraEnabled(cacheable=true). Vous ne pouvez mettre en cache les résultats que pour les méthodes qui récupèrent des données sans les modifier. Cette annotation supprime le besoin d’appeler setStorable() dans le code JavaScript à chaque action appelant la méthode Apex.
En API version 55.0 et suivantes, vous pouvez utiliser l’annotation @AuraEnabled(cacheable=true scope='global') pour permettre la mise en cache des méthodes Apex dans un cache global.
global with sharing class TestClass{
@AuraEnabled
global static void testMethod{}
}
Vous pouvez référencer cette méthode depuis un autre package dans
votre Lightning Web Component comme ceciimport logExceptionLWC from "@salesforce/apex/TestClass.testMethod";
Une des astuces les plus importantes concerne les modèles personnalisés dans votre code Apex. Si vous devez plus tard les sérialiser ou désérialiser, vous devrez ajouter l’annotation Json Access à votre modèle personnalisé. Astuce : pensez aussi à ajouter l’annotation aux objets enfants ;)
Qu’est-ce que l’annotation Json Access ? Et quelles sont ses options et considérations de sérialisation et désérialisation ?
L’annotation @JsonAccess définie au niveau d’une classe Apex contrôle si les instances de la classe peuvent être sérialisées ou désérialisées. Si l’annotation restreint la sérialisation et désérialisation JSON, une exception runtime JSONException est levée.
Les paramètres serializable et deserializable de l’annotation @JsonAccess imposent les contextes dans lesquels Apex autorise la sérialisation et la désérialisation.
Vous pouvez définir un ou deux paramètres, mais vous ne pouvez pas utiliser l’annotation sans paramètre. Les valeurs valides pour indiquer si la sérialisation et la désérialisation sont autorisées :
Si une classe Apex annotée avec JsonAccess est étendue, la classe étendue n’hérite pas de cette propriété. Si la méthode toString est appliquée à des objets qui ne doivent pas être sérialisés, des données privées peuvent être exposées. Vous devez surcharger la méthode toString sur les objets dont les données doivent être protégées. Par exemple, sérialiser un objet stocké comme clé dans une Map invoque la méthode toString. La map générée inclut des entrées key (string) et value, exposant ainsi tous les champs de l’objet.
@JsonAccess(serializable='always' deserializable='always')
global class FullDetails{
global String fullName {get; set;}
global Address address {get; set;}
@JsonAccess(serializable='always' deserializable='always')
global class Address{
global String streetName {get; set;}
global String postalCode {get; set;}
}
}
Et si vous créez des classes Apex non packagées dans votre projet et que vous devez référencer une autre classe Apex ou une interface faisant partie du managed package ? Assurez-vous simplement de définir ces classes comme global et de référencer la classe avec <Namespace>.<ClassName>
La référence de callout habituelle serait callout:<NamedCredentialsApiName>, mais si vous utilisez des named credentials dans votre package pour vos classes de callout, vous devrez la mettre à jour en callout:<NampeSpace>__<NamedCredentialsApiName>
Si vous ajoutez le composant connected app à votre package, voici les étapes exactes pour le faire et éviter certains bugs courants.
<?xml version="1.0" encoding="UTF-8"?> <ConnectedApp xmlns="http://soap.sforce.com/2006/04/metadata"> <developerName>YourNamespace__ConnectedAppName</developerName> <contactEmail>ConnectedAppContactEmail</contactEmail> <label>ConnectedAppLabelName</label> <version>ConnectedAppVersion</version> </ConnectedApp>
Si vous avez suivi exactement les mêmes étapes et que la création de la version de package échoue avec cette erreur :
ERROR running force:package:version:create: <ConnectedAppName>: Installing an app (<ConnectedAppName>) that has been deleted.
Croyez-moi, nous sommes déjà passés par là. Vous devrez d’abord créer un nouveau package, puis une nouvelle version de package. Pour valider cela avant de commencer, créez un nouveau projet dx factice, créez un nouveau package, ajoutez la même connected app déjà créée, puis créez votre version de package et dites-moi si cela fonctionne pour vous.
Enfin, vous devez parcourir tous vos champs, objets, triggers, permission sets, custom metadata, etc. et ajouter <Namespace>__
Si vous trouvez une erreur similaire provoquant l’échec de l’installation de votre package dans un environnement, au lieu de passer des heures ou des jours à comprendre, supprimez simplement ces Quick Actions standard de votre layout, puis rajoutez-les une fois le package installé avec succès.
(ObjectName-Layout) In field: QuickAction - no QuickAction named NewCase found
(ObjectName-Layout) In field: QuickAction - no QuickAction named NewTask found
(ObjectName-Layout) In field: QuickAction - no QuickAction named LogACall found
Component [flexipage:filterListCard] attribute [filterName]: Error retrieving filter [My_ChatterGroups] for entity [CollaborationGroup]
Autre point à considérer : si votre code source dépend de composants Salesforce intégrés, assurez-vous de donner accès à ces composants dans vos étapes de pré-déploiement avant l’installation de la version du package. Comme ici, l’activation d’omni channel.
Your org doesn't have access to component runtime_service_omnichannel:omniWidget.
Enfin, si vous avez des standardValueSets dans votre code source et que les metadata de votre version de package en dépendent, veillez à déployer ces value sets comme étape de pré-déploiement avant l’installation de la version de package. Comme ici, le déploiement d’une valeur de pick-list de statut personnalisée nommée TestValue.
Component [lst:dynamicRelatedList] attribute [adminFilters]: TestValue isn't a valid picklist value.
Vous pouvez consulter la Metadata Coverage Documentation pour savoir quels composants sont packageables.
Planifier une démo pour découvrir comment Serpent peut renforcer votre stratégie Salesforce DevOps dès aujourd’hui. Serpent de Tekunda propose d’excellents outils pour aider vos équipes DevOps, notamment le contrôle de version intégré, les systèmes de déploiement continu et de release, les outils de merge et de nombreux outils de test.

Andrew Hanna

Serpent Team

Tekunda Team

Tekunda Team

Tekunda Team

Andrew Hanna