Apex Coding Fundamentals
Apex Coding Fundamentals
01 public interface PurchaseOrder { 02 03 } 04 05 06 07 08 09 10 11 } public Double discount() { return DEFAULT_DISCOUNT; static final double DEFAULT_DISCOUNT = .05; public class CustomPurchaseOrder implements PurchaseOrder { Double discount();
12 13 }
The implements keyword is used to indicate interface implementation, the static keyword indicates a class variable (or method) accessible without an instance of the class, and the final keyword indicates a constant. You can create an instance of a class using the new keyword. For example:
primitive data types such as Integer and Date sObject types that represent persistent objects collections and enumerations user and system-defined Apex classes Blob - for storing binary data Boolean Date, Time and Datetime Decimal - for representing arbitrary precession numbers, including currency ID - the Force.com database record identifier type Integer, Long, Double and String
Here are some variable definitions for primitives that should give you a feeling for using these data types:
1 2
Map<String,String> myStrings = new Map<String,String>{'a'= >'b','c'=>'d'.toUpperCase()}; Map<ID,Contact> m = new Map<ID, Contact>([select id, lastname from contact]);
That last statement contains a sneak peek of the database integration, populating the map with retrieved contact objects, which in turn only have their id and lastname fields populated. Apex also supports enumerations. The following code creates a new data type called Season, then declares a variable of that data type, and assigns it a value.
03 04 05 }
System.debug(count); count++;
06 for (Integer i = 0, j = 0; i < 10;i++){ 07 08 } 09 Integer[] myInts = new Integer[]{1,2,3,4,5,6,7,8,9,10}; 10 for (Integer i : myInts) { 11 12 }
The last for loop shows how to iterate over a collection. Apex also supports a special loop for iterating over persisted sObject records returned by a query:
System.debug(i+1);
System.debug(i);
1 String s = 'Acme'; 2 3 4}
Note how the query is embedded in square brackets, and how it makes a reference to the variables. Exceptions Apex uses the familiar throw, try, catch and finally statements to handle exception flows. For example:
for (Account a : [select id, name from account where name like :(s+'%')]){ //Your code
5 } catch(Exception e) { 6 7}
Miscellaneous Syntax
Apex supports a couple of annotations. The @future annotation identifies methods that are executed asynchronously, and the@isTest annotation is a class annotation that indicates that all the methods are test methods (covered later). The following example shows using @future for making an asynchronous web services call:
sObject is also the name of the generic abstract type that can be used to represent any persisted object type. Assuming the database has an Account sObject, with fields for name and billingcity, then either of the following two lines will create an
sObject:
Note the optional use of initial field values in the final example. Apex provides a convenient dot notation for accessing fields within an object, so the following will return the identifier and string of an account object:
1 String x = a.get('name');
Queries and Embedded Queries The Force.com platform supports two query languages: Salesforce Object Query Language (SOQL) is a query-only language. While similar to SQL in some ways, it's an object query language that uses relationships, not joins, for a more intuitive navigation of data. You'll see an example in a minute. y Salesforce Object Search Language (SOSL) is a simple language for searching across all persisted objects. These languages can be embedded in your Apex code, making data retrieval easy. This code retrieves an sObject (a record from the database) that has the name field assigned to Acme:
y
This code retrieves all matching accounts (assuming that there'll be zero or more), assigning them to a list:
1 String myName = 'Acme'; 2 Account [] accts = [select ID from Account where name=:myName];
The following code retrieves the first matching account and assigns the annualRevenue field value to a variable:
If you have an Account and Contact sObject in a relationship, you can traverse the relationship in the query using the dot notation. This code retrieves the name of the related Account sObject via the Contact sObject:
SOSL statements evaluate to a list of lists of sObjects, where each list contains the search results for a particular sObject type. Here's an example that searches across the name field of all Account and Contact sObjects:
List<List<SObject>> searchList= [FIND 'map*' IN NAME FIELDS RETURNING Account (id, name),Contact];
1 2 3
for (Account[] tmp : [select id from Account where name= 'yyy']){ j = tmp.size(); // perform some actions on the accounts
4}
Triggers Triggers are written in Apex, and execute before or after an insert, update, delete or undelete event occurs on an sObject. The syntax that introduces a trigger definition will look a little familiar, and begins with the trigger keyword:
01 02 03 04 05 06
trigger myAccountTrigger on Account (before insert, before update) { if (Trigger.isInsert) { // } if (Trigger.isUpdate) { for(Account a: Trigger.new)
07 08 09 10 }
This example fires before any Account sObject is inserted or updated. The Trigger.new context variable provides access to the list of accounts being inserted or updated. Update and delete triggers can use Trigger.old to refer to the old versions of the objects being updated or deleted. Triggers make full use of Apex, allowing you to continue using a familiar language for data manipulation. There are a few restrictions - for example it doesn't make sense to allow call outs to web services from within a trigger as that would unduly lengthen the transaction. Data Manipulation Language Apex code can also contain data manipulation language (DML) operations to retrieve, insert, delete and update data in the database. You can also create and manipulate save points. Here are some examples:
01 public class myClass { 02 03 04 static testMethod void myTest() { Account a = new Account(name='foo'); insert a;
05 06 07 08 09 10 11 12 13
System.assertEquals('foo', [select name from Account where id=:a.id].name); System.assertEquals(1, [select count() from Account where id=:a.id]); try { delete a; Foo.myMethod(a); //call some method } catch (DmlException e) { System.assert(false); never get here } } // assert that we should
14 }
These tests typically use the System.assert() series of methods to flag code behavior and catch all exceptions. Apex as a Controller Language Visualforce is the user interface layer on the Force.com platform. It provides a modelview-controller (MVC) paradigm to creating user interfaces, where incoming web requests (from a browser, say) can be routed to a controller that can perform certain actions, and then display a result. Visualforce controllers and extensions must be written in Apex. These controllers typically look no different to the Apex code appearing in this article, though they do have access to additional data types, classes, methods and properties. For example, in Visualforce controllers you have access to page parameters, and Visualforce pages themselves are first-class citizens within Apex, allowing you to redirect to various pages, render the pages as PDF and email as a blob, and so on. Here's a simple controller:
4 0 5 0 6 07 08 09 10 11
!= null) { where = Page.foo; where.setRedirect(true); } else { where = Page.bar; where.getParameters().put('p', 'nowHasParam'); } return where;
12 } PageReference is the data type of a Visualforce page, and this code examines the
parameters of the current page and redirects to one of two other pages depending on what it finds. Such controllers can also execute DML, query the database and return results for example. Web Services Apex makes it easy to invoke external web services, and to expose methods in an externally-available web service endpoint. Exposing Web Services Apex methods can easily be exposed as custom Force.com Web Services API calls, allowing them to be called from external applications. For example, the following code exposes a method as a service using the webService keyword:
1 global class MyWebService { 2 3 4 5 6 7} } webService static Id makeContact(String lastName, Account a) { Contact c= new Contact(lastName= 'Weissman',AccountId = a.Id); insert c; return c.id;
The global access modifier declares that the class is visible to all Apex code, everywhere. Any class that uses Web services must be defined as global. The web service will be immediately available on the Force.com platform. To call it, you'll simply need the automatically generated WSDL for the service, which can be found by navigating to the class using the Force.com Builder environment, clicking on the name of the class and then clicking the Generate WSDL button. You can feed the generated WSDL document to your language of choice, and call into the Apex Web service on the Force.com platform. Calling External Web Services The Force.com platform makes it easy to call an external SOAP web service by automatically generating the support Apex for you. To do this you need to feed the platform the WSDL of the external web service that you want to access, using the Force.com Builder environment. As an example, navigate to Setup-> Develop->Apex Classes and click the Generate from WSDL button. Specify a WSDL document in the wizard. The platform uploads and parses the WSDL. If the WSDL contains supported schemas and types, you can use the resulting Apex classes to call that web service. For example, the following code makes a call to an external web service:
many programming needs. Here's an example that determines whether an sObject or list of sObjects is of a particular data type:
1 //Create a generic sObject variable s 2 SObject s = [select id from account limit 1]; 3 //Verify if that sObject variable is an Account token 4 System.assertEquals(s.getSObjectType(), Account.sObjectType);
5 //Create a list of generic sObjects 6 List<sObject> l = new Account[]{}; 7 8 //Verify if the list of sObjects contains Account tokens
System.assertEquals(l.getSObjectType(),Account.sObjectTy pe); You can similarly retrieve a token for a field (in this case AccountNumber) of an
Object:
1 Schema.SObjectField F = Account.AccountNumber;
Instead of the compile time tokens, you can use runtime calls to a set of getDescribe() methods to introspect sObjects. For example, if you had an Account object that has an Industry field that is a picklist, you can determine the possible values of the picklist, and all child relationships of the sObject, like so:
Schema.DescribeFieldResult f = Account.Industry.getDescribe();
The returned information is quite comprehensive. For example, for a field you can determine everything from whether the field is an ID or a Name field, to whether it's nillable, unique, case sensitive or its precision (if it's of type Double). Dynamic Queries Dynamic SOQL refers to the creation of a SOQL string at runtime from within Apex. This article typically uses the compile-time construction, for example:
You can create a dynamic query by making a call to the query() method on the database, passing in a string (which you can dynamically construct of course). For example, you can run the following dynamic SOQL query:
The same method can be used for dynamic SOSL queries. Miscellanea While Apex provides a very familiar programming environment, with tight integration to a web services stack and database, it's also somewhat unusual in the sense that it runs in the cloud. Compiling an Apex class means somehow getting that class to the Force.com platform, which will in turn compile it and either produce the compiled code (which you don't generally access) or error messages. There are also consequences of running in the cloud in a multi-tenant environment. This section examines these aspects of Apex. Development as a Services You can think of Apex itself as metadata in a complete application, together with the definition of sObjects, workflow rules, triggers and so on. The platform can be fed all this metadata, and it is turned into an application running in the cloud. Development as a Service (DaaS) is a suite of features enabling the use of traditional development practices for creating on-demand applications. When creating an application on the Force.com platform you have two main conduits:
y
The Force.com Builder - which is an environment that you access through your web browser that lets you configure the platform and all aspects of your application. For example, you can use this environment to create sObjects, create Apex classes and view the result. The Metadata API - a web service that lets you access all the metadata associated with your application through a special web services endpoint.
This latter option opens up a host of opportunities. For example, the Force.com IDE provides a traditional Eclipse-based integrated development environment for writing Apex (and other components of the platform). The IDE provides syntax highlighting, compilation, error handling, test method execution and so on, and it does it by invoking the metadata API under-the-hood. To compile a piece of code, it sends the code to the platform, which compiles it and returns any resulting metadata to the IDE. You can access this metadata more directly through the Force.com Migration Tool or by writing your own interface to the metadata API, providing a number of interesting opportunities. For example, you can migrate code from one environment to another (Force.com provides sandboxes and development environments, as well as production environments) simply by pulling all the metadata from the metadata API, and then pushing it to the other environment using the same API.
Multi-tenancy The Force.com platform is a multi-tenant platform, which means that the resources used by your application (such as the database) are shared with many other applications. This multi-tenancy has a lot of benefits, and it comes with a small promise on your part. In particular, if you write Apex code, the platform needs to do its best to ensure that it is well behaved. For example, Apex code that simply loops will not benefit you (or the cloud). This is the reason why Apex, when deployed to a production server, needs 75% code coverage in tests. The Apex runtime engine also enforces a number of limits to ensure that runaway Apex does not monopolize shared resources. These limits, or governors, track and enforce various metrics. An example of these limits include (at the time of writing): the total stack depth for an Apex invocation in a trigger is 16, the total number of characters in a single String may not exceed 100000, and the total number of records processed as a result of DML statements in a block may not exceed 10000. There are various precautions that can be taken to ensure that the limits are not exceeded. For example, the batched for loop described earlier lifts certain limits, and different limits apply depending on what originated the execution of the Apex. For example, Apex originating from a trigger is typically more limited than Apex that started running as part of a web services call. Summary This article provides an overview of Apex, a modern object-oriented programming language for on-demand computing. Apex provides a tight integration with the Force.com database, making it very easy to manipulate and query data right from within Apex itself. Apex is also used to code triggers that fire when database objects are manipulated, and it is used in the controllers of the user interface layer provided by Visualforce. Apex also provides simple access to web services. The platform can automatically generate Apex to access external web services, and it's particularly easy to write a web service in Apex itself. As a language for programming a platform in the cloud, Apex also provides additional facilities such as a comprehensive Metadata API for manipulating Apex and other metadata, as well as traditional development environments such as the Force.com IDE. It also provides governors and limits, and a testing framework to ensure that Apex code is well-behaved in a multi-tenant environment. For a more comprehensive introduction see the Apex Language Reference below. References
y y y y y
Developer Force provides access to free developer edition accounts, which you can use to start programming in Apex immediately. It also provides links to documentation, forums, and more. The Apex Language Reference provides a comprehensive introduction to the Apex language, providing a lot more detail on all topics covered in this document. An Introduction to the Force.com Database provides a much more comprehensive introduction to the Force.com Database. Read An Introduction to Apex Code Test Methods to learn more about writing unit tests. Learn all about Governors in Apex Code The Force.com IDE page provides access to the Force.com IDE and its documentation, which you can use to code Apex from an integrated development environment.