Sei sulla pagina 1di 15

An Introduction to Force.

com Apex Code


Abstract Force.com Apex Code is a strongly-typed programming language that executes on the Force.com platform. Apex is used to add business logic to applications, to write database triggers, and to program controllers in the user interface layer. It has a tight integration with the database and query language, good web services support, and includes features such as futures and governors for execution in a multi-tenant environment. This article introduces the Apex language. After providing an overview of the syntax, we look at its database support, followed by testing, web services, and dynamic apex. Finally, we look at development as a service and other consequences of the Apex language executing on the Force.com platform. After reading this article you will have a good overview of the language and its use on the platform. Syntax Apex has a syntax that will be familiar to Java and C# programmers. It has the usual array of features such as classes, interfaces, constants, class variables, and annotations. Unusually, Apex is not case sensitive. Classes and Interfaces Here is a simple example of an interface and a class implementing the interface:

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:

1 PurchaseOrder po = new CustomPurchaseOrder();


Apex supports the standard Java-like notions of this and instanceOf. Primitive Data Types Apex supports a number of different data types:
y y y y

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

The primitive data types include:


y y y y y y

Here are some variable definitions for primitives that should give you a feeling for using these data types:

1 DateTime dt = System.now() + 1; 2 Boolean mustI = true; 3 String s = 'abc'.toUpperCase(); 4 Decimal d = Decimal.valueOf('123');


Note that the String data type uses single quotes, not double quotes. Collections Apex supports Sets, Lists and Maps, as well as enumerations. These are pretty straightforward, so we'll just provide a few examples here. Note that the first element of a collection is at index position zero. A set is an unordered collection of primitives that does not contain any duplicate elements:

1 Set<String> s = new Set<String>{'a','b', 'c'}; 2 s.add('c'); 3 System.assert(s.contains('b')); 4 System.assert(s.size() == 3);


A list is a collection of elements. Use a list when the sequence is important. You can have duplicates in a list:

1 List<Integer> myList = new List<Integer>(); 2 myList.add(47); 3 myList.get(0);


You can also use the array syntax for lists. For example:

1 String [] colors = new List<String> (); 2 colors[3] = 'Green';


Maps are collections of key-value pairs, and support a shortcut syntax for populating the collection:

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.

1 public enum Season {WINTER, SPRING, SUMMER, AUTUMN} 2 Season s = Season.AUTUMN;


Statements and Expressions Although we've already seen instances of statements and expressions, it's worth showing a few more examples just to give a taste.

01 Integer count = 1; 02 while (count < 11) {

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

1 try { 2 Throw new Exception();

3 } catch(ListException e) { 4 //List Exception handling code here

5 } catch(Exception e) { 6 7}
Miscellaneous Syntax

//Generic exception handling code here

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:

1 @future(callout=true) 2 public static void doCalloutFromFuture(){ 3 4}


You cannot create your own annotations. Finally, Apex also supports an abbreviated property syntax. For example, to declare a variable as well as its associated getters and setters, you can write something like the following:

//Executes when the platform has resources

1 2 public Integer prop { 3 4 5}


The simplest property definition takes this form:

get { return prop * 2; } set { prop = value; }

1 public Integer anotherProp {get;set;}


Database Integration Apex has strong ties with the Force.com persistence layer, the database. In this section we'll show how the language can be used to create, persist and update database objects (called sObjects), as well as query the database and iterate over results. It is also used for writing database triggers. For a more comprehensive introduction to the Force.com database and the services it offers, see An Introduction to the Force.com Database. Manipulating sObjects sObjects refers to any object that can be stored in the Force.com platform database. These are not objects in the sense of instances of Apex classes; rather, they are representations of data that has, or will be, persisted. These persisted objects can be treated as first class citizens within the Apex language, which makes the database integration particularly intuitive and easy to use.

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:

1 sObject s = new Account(); 2 Account a = new Account( name='Acme', billingCity='Edinburgh');

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 ID id = a.ID; 2 String x = a.name;


Dynamic Apex allows you to employ a loosely typed syntax, for example the last statement could be rewritten as:

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

sObject s = [select id, name from account where name='Acme'];

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:

Double rev= [select annualRevenue from Account where name = 'Acme'][0].annualRevenue;

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:

Contact c= [select Account.name from Contact where id =:id] ;

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];

2 Account [] accounts= ((List<Account>)searchList[0]); 3 Contact [] contacts= ((List<Contact>)searchList[1]);


Queries can also be embedded in the special for syntax. This syntax can also be used to loop through batches of returned records, as shown below:

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 }

if (a.name == 'bad') a.name.addError('Bad name'); // prevent update }

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:

Account[] accounts = new account[] {new Account(name='foo'), new Account(name='bar')};

2 insert accounts; 3 Savepoint sp = Database.setSavepoint(); 4 delete accounts; 5 Database.rollback(sp);


Testing The Force.com platform requires that at least 75% of your Apex classes are covered by testing before code can be deployed to a production system. Ideally, you should strive for 100% coverage. As a result, Apex development usually goes hand in hand with unit test development. This restriction isn't in place in the development edition organization. In Apex, test methods are denoted with the testMethod keyword. Here's an example of a class that provides a test method:

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:

01 public class MyController { 02 0 3 0 PageReference where; public PageReference dynamicJump() { if (ApexPages.currentPage().getParameters().get('p')

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:

AcmeServices.grabService gs = new AcmeServices.grabService();

2 String result = gs.doLookup('some data');


As you can see, this is standard Apex - all the hard work lies in the generation of the Apex classes from the WSDL document, which is done for you by the platform. Dynamic Apex Dynamic Apex refers to two mechanisms that allow you to construct programs that provide dynamic behavior. In particular, you can, at runtime, introspect Objects and use this information to react dynamically to the particular object. You can also write dynamic SOQL and SOSL queries, where the queries are constructed at runtime. This section looks at these two items in a little more depth. Introspecting sObject Information Objects contain metadata, such as their name, field names and types, default field values and so on. You can write applications that introspect this information and change the behavior based on what is discovered. There are two types of introspection: compile time introspection, and runtime introspection. In compile time introspection you create tokens that represent information about the metadata of an sObject. These tokens are serializable and lightweight, and are ideal for

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();

2 List<Schema.PicklistEntry> p = f.getPicklistValues(); 3 List<Schema.ChildRelationship> c = f.getChildRelationships ();

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:

1 Contact c = [select Account.name from Contact];

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:

sObject c = Database.query('select Account.name from Contact limit 1');

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.

Potrebbero piacerti anche