Saturday, 8 June 2019

Different Annotations in Apex



Apex supports the following annotations:

1. @Deprecated
2. @Future
3. @IsTest
4. @ReadOnly
5. @RemoteAction
6. @TestVisible

Apex REST annotations:

1. @RestResource(urlMapping='/yourUrl')
2. @HttpDelete
3. @HttpGet
4. @HttpPatch
5. @HttpPost
6. @HttpPut



@ReadOnly annotation :
======================
The @ReadOnly annotation allows you to perform unrestricted queries
against the Force.com database.

All other limits still apply.

it's important to note that this annotation, while removing the
limit of the number of returned rows for a request, blocks you
from performing the following operations within the request :
1.DML operations,
2.call to system.schedule
3.calls to method annotated with @future
4. sending emails.

Note : only webservice, RemoteAction and Schedulable.execute()
methods can be marked readonly.

ex:

public class TestVFPage{
 @RemoteAction
 @readonly
 public static List<Task> getTask(){
   return [select Id from Task];
 }

}

<apex: page controller="TestVFPage">
  <script>
   Visualforce.remoting.Manager.invokeAction( 
   '{!$RemoteAction.TestVFpage.getTask}',
                        function(result){
                            alert('Total Records: '+result.length);
                        }
   );
  </script>
  <div id="totalAccounts" ></div>
</apex:page>


ex 2 :


 global class DuplexScheduler implements Schedulable 
 { 
   public String aggregatorQuery; 
   public String fieldInQuery; 
    global DuplexScheduler() 
    { 
      aggregatorQuery = 'Select Count(Id),Name from teacher__c Group By Name Having Count(Id)>1'; 
      fieldInQuery = 'Name'; 
    } 
   @ReadOnly 
   global void execute (SchedulableContext ctx) 
   { 
   String body = fieldInQuery; 
   for(AggregateResult res : database.query(aggregatorQuery)) 
   { 
     body += '\n'+String.valueOf(res.get(fieldInQuery)); 
   } 
   System.debug('****body'+body); 
   } 
 } 

 Note : To use the @readonly annotation, the top level request
 must be in the schedule execution or the web service invocation .

 For example , if a visualforce page calls a web service that
 contains the @Readonly annotation , the request fails because
 visualforce is the top level request, not the web service.

 @AuraEnabled Annotation :
 =========================
 1.Use @AuraEnabled on Apex class static methods to make them accessible as
 remote controller actions in your Lightning Components.
 2.Use @AuraEnabled on Apex instance methods and properties to make them serializable
 when an instance of the class is returned as data from a server-side
 action.

 ex :
    public class classController {

@auraEnabled
public List<account> lstOfAccount{get;set;}

@AuraEnabled
    public static classController initClass(){
   classController obj = new classController();
       obj.lstOfAccount = [select id,name from account LIMIT 10];

       // return class instance
       return obj ;
     }
}

 @Future Annotation :
 ======================
 Use the future annotation to identify methods that are executed
 asynchronously. When you specify future, the method executes
 when salesforce has available resource.
 ex :

 public class AccountProcessor
{
  @future
  public static void countContacts(Set<id> setId)
  {
      List<Account> lstAccount = [select id,Number_of_Contacts__c , (select id from contacts ) from account where id in :setId ];
      for( Account acc : lstAccount )
      {
          List<Contact> lstCont = acc.contacts ;
         
          acc.Number_of_Contacts__c = lstCont.size();
      }
      update lstAccount;
  }
}

@InvocableMethod Annotation :
===============================
While the Process builder is very flexible out of the box,there
are few business use cases those are not achievable using it.

For example

1. It doesn't support outbound messages.
2. it doesn't support creation of multiple records.
3. It doesn't support us to delete a record.

when no other process action can get the job done, add
customized functionality to your salesforce processes by
calling an Apex method.

To call an APex method , add the Call Apex action to your
process and select an Apex class with an @invocable method
Annotation.

It means they allows us to extend the Process Builder by writing Apex code
that meets certain criteria, and then invoking the Apex from our
Processes.

If the class contains one or more invocable Variables,
manually enter values or reference field values from the related
record.

@InvocableMethod Annotation support bulk operations.



 ex:

 public class DeleteUnacceptedQuotes
 {
  @InvocableMethod
  public static void QuoteDelete(List<Id> oppIds){
    List<Quote> quotes =[select Id from Quote where
                      Opportunity.Id in : oppIds
  and Status !='Accepted'];
delete quotes;  
 
  }

 }

 ex 2 :

public class InvocableSetQ
{
  @InvocableMethod
  public static void SetQ(List<Id> ListID)
  {
    List<Object__c > bidR=[select id , Attribute__c from Object__c where id in :ListID];
    for (Object__c b:bidR )
{
  b.ownerid = c.Queue_ID__c  ;
}
    update bidR;
   
  }
}


@InvocableVariable Annotation :
===============================
To invoke apex from process builder , we have to use annotations
" InvocableMethod" for method and "InvocableVariable" for variable.

ex :

global class InvocableMethodcls {

// An invocable variable used as input or output variables in the process builder

 global class ActionRequest{
  @InvocableVariable(required=true)
  public ID leadId;
  @InvocableVariable
  public string phone;
  @InvocableVariable
  public string email;
  @InvocableVariable
  public Lead leadobj;
  @InvocableVariable
  public string firstName;
  @InvocableVariable
  public string lastName;

 }
 // This invocable method is used for processing the business by taking the input from Process builder

 @InvocableMethod(label='Invoke Business Logic')
 global static void invokeService(List<ActionRequest> requests){
    for(ActionRequest requestObj:requests){
   //Accessing the values from process builder when record is inserted
            System.debug('requestObj.leadId@@:'+requestObj.leadId);
System.debug('requestObj.firstname@@:'+requestObj.firstname);
            System.debug('requestObj.lastname@@:'+requestObj.lastname);     
           
                     
}

// we can write our own business logic here
 }

}

@isTest Annotation :
=====================
Use the @isTest annotation to define classes and methods
that only contains code used for testing your application.

@isTest
private class MyTestClass {

   // Methods for testing
   @isTest static void test1() {
      // Implement test code
   }

   @isTest static void test2() {
      // Implement test code
   }

}

@testSetup Annotation :
=======================
To Set up test Data for an Entire Test class in Salesforce,@testSetupis used.

Note : @testSetup avoids creation of same set of records to be used in
different test methods in the same test class

ex :

@isTest
private class CommonTestSetup {
 /* Method to setup data */
    @testSetup static void setup() {
        /* Create common test Accounts */
        List<Account> testAccts = new List<Account>();
        for(Integer i=0;i<2;i++) {
            testAccts.add(new Account(Name = 'TestAcct'+i));
        }
        insert testAccts;   

   /* Create common test Contacts */
        List<Contact> testContacts = new List<Contact>();
        for(Integer i=0;i<2;i++) {
            testContacts.add(new Contact(FirstName = 'TestAcct'+i, LastName = 'TestAcct'+i));
        }
        insert stName = 'TestAcct'+i; 
    }

    @isTest static void testMethod1() {
        /* Testing class with Accounts and Contacts */
    }

    @isTest static void testMethod2() {
        /* Testing class with Contacts */
 
    }
}

@TestVisible Annotation :
=========================
TestVisible annotation  allows test methods to access private or
protected members of another class outside the test class.
These members include methods , member variables, and inner classes.

ex :

public class TestVisibleExample {
    // Private member variable
    @TestVisible private static Integer recordNumber = 1;

    // Private method
    @TestVisible private static void updateRec() {
    }


@isTest
private class TestVisibleExampleTest {
    @isTest static void test1() {
        // Accessing private variable annotated with TestVisible
        Integer i = TestVisibleExample.recordNumber;
        System.assertEquals(1, i);

        // Accessing private method annotated with TestVisible
        TestVisibleExample.updateRecord();
    }
}

@Deprecated Annotation :
==========================

Use the deprecated annotation to identify methods, classes, exceptions, enums, interfaces, or variables that can no longer be referenced in subsequent releases of the managed package in which they reside.
This is useful when you are refactoring code in managed packages as the requirements evolve. New subscribers cannot see the deprecated elements, while the elements continue to function for existing subscribers and API integrations.

@RemoteAction Annotation :
==========================

Javascript remoting in visualforce provides support for
some methods in Apex controllers to be called via javascript.



ex :

global class sample
{
    public String accountName { get; set; }
    public static Account account { get; set; }
    public sample() { }
   
    @RemoteAction
    global static Account getAccount(String accountName)
    {
        account = [select id, name, phone, type, numberofemployees from Account where name = :accountName ];
        return account;
    }
}

<apex:page controller="sample">
    <script type="text/javascript">
    function getAccountJS()
    {
        var accountNameJS = document.getElementById('accName').value;       
        sample.getAccount( accountNameJS,
        function(result, event)
        {
            if (event.status)
            {
                // demonstrates how to get ID for HTML and Visualforce tags
                document.getElementById("{!$Component.theBlock.thePageBlockSection.theFirstItem.accId}").innerHTML = result.Id;
                document.getElementById("{!$Component.theBlock.thePageBlockSection.theSecondItem.accNam}").innerHTML = result.Name;
            }
            else if (event.type === 'exception')
            {
                document.getElementById("errors-js").innerHTML = event.message;
            } else
            {
                document.getElementById("errors-js").innerHTML = event.message;
            }
        }, {escape:true});
    }
    </script>
    Account Name :<input id="accName" type="text" />
    <button onclick="getAccountJS()">Get Account</button>
    <div id="errors-js"> </div>
    <apex:pageBlock id="theBlock">
        <apex:pageBlockSection id="thePageBlockSection" columns="2">
            <apex:pageBlockSectionItem id="theFirstItem">
                <apex:outputText id="accId"/>
            </apex:pageBlockSectionItem>
            <apex:pageBlockSectionItem id="theSecondItem" >
                <apex:outputText id="accNam" />
            </apex:pageBlockSectionItem>
        </apex:pageBlockSection>
    </apex:pageBlock>
</apex:page>

Note :

1. we can return value to the visualforce page i.e callback.
2. we can call the apex methods fromany apex class.
3. Remote function can submit the form.

@SuppressWarnings Annotation :
===============================
The @SuppressWarnings annotation does nothing in Apex but can be used
to provide information to third party tools.

PMD has way to suppress warnings in Apex.

Note : PMD ( programming Mistake Detector)

Using @SuppressWarnings, which works on any element that is annotateable
(classes,fields,methods etc).

ex :

// This will suppress all the PMD warnings in this class
@SuppressWarnings("PMD")
public class Bar {
    void bar() {
        int foo;
    }
}

@RestResource Annotation :
==========================
The @RestResource annotation is used at the class level
and enables you to expose an Apex class as a REST resource.
@RestResource is at the class level.It is used to expose a
class as rest source.

ex :

Apex REST annotations:

1. @RestResource(urlMapping='/yourUrl')
2. @HttpDelete
3. @HttpGet
4. @HttpPatch
5. @HttpPost
6. @HttpPut

ex :

@RestResource(urlMapping='/Account/*')
global with sharing class sampleRest {
 
    @HttpGet
    global static Account doGet() {
        RestRequest req = RestContext.request;
        String memberId = req.requestURI.substring(req.requestURI.lastIndexOf('/') + 1);
        Account result = [SELECT Id, Name FROM Account WHERE Id = :memberId];
        return result;
    }
 
    @HttpPost
    global static String doPost(String name, String descrp) {
        Account a = new Account(Name = name, Description = descrp);       
        insert a;
        return a.Id;
    }

    @HttpDelete
    global static void doDelete() {
        RestRequest req = RestContext.request;
        String memberId = req.requestURI.substring(req.requestURI.lastIndexOf('/') + 1);
        Account memb = [SELECT Id FROM Account WHERE Id = :memberId];
        delete memb;
    }
   
}

No comments:

Post a Comment