salesforce: Spring ’13Force.com Apex Code Developer's Guide Last updated: May 3, 2013 © Copyright 2000–2013 salesforce.com, inc. All rights reserved. Salesforce.com is a registered trademark of salesforce.com, inc., as are other names and marks. Other marks appearing herein may be trademarks of their respective owners. Table of Contents Table of Contents Chapter 1: Introducing Apex................................................................................................................1 What is Apex?...........................................................................................................................................................................2 How Does Apex Work?................................................................................................................................................3 What is the Apex Development Process?......................................................................................................................4 Using a Developer or Sandbox Organization.....................................................................................................4 Learning Apex...................................................................................................................................................7 Writing Apex.....................................................................................................................................................8 Writing Tests.....................................................................................................................................................9 Deploying Apex to a Sandbox Organization...................................................................................................10 Deploying Apex to a Salesforce Production Organization...............................................................................10 Adding Apex Code to a Force.com AppExchange App..................................................................................10 When Should I Use Apex?..........................................................................................................................................11 What are the Limitations of Apex?.............................................................................................................................11 What's New?...........................................................................................................................................................................12 Apex Quick Start.....................................................................................................................................................................12 Documentation Typographical Conventions...............................................................................................................12 Understanding Apex Core Concepts...........................................................................................................................13 Writing Your First Apex Class and Trigger................................................................................................................18 Creating a Custom Object...............................................................................................................................18 Adding an Apex Class.....................................................................................................................................19 Adding an Apex Trigger..................................................................................................................................20 Adding a Test Class.........................................................................................................................................21 Deploying Components to Production............................................................................................................23 Chapter 2: Language Constructs.........................................................................................................25 Data Types..............................................................................................................................................................................26 Primitive Data Types...................................................................................................................................................26 sObject Types..............................................................................................................................................................29 Accessing sObject Fields..................................................................................................................................30 Accessing sObject Fields Through Relationships............................................................................................31 Validating sObjects and Fields .......................................................................................................................32 Collections...................................................................................................................................................................33 Lists.................................................................................................................................................................33 Sets..................................................................................................................................................................38 Maps................................................................................................................................................................40 Parameterized Typing......................................................................................................................................41 Using Custom Types in Map Keys and Sets....................................................................................................41 Iterating Collections........................................................................................................................................44 Enums.........................................................................................................................................................................44 Understanding Rules of Conversion............................................................................................................................46 Variables..................................................................................................................................................................................47 i Table of Contents Case Sensitivity............................................................................................................................................................48 Constants.....................................................................................................................................................................48 Expressions..............................................................................................................................................................................49 Understanding Expressions.........................................................................................................................................49 Understanding Expression Operators..........................................................................................................................50 Understanding Operator Precedence...........................................................................................................................56 Extending sObject and List Expressions.....................................................................................................................56 Using Comments.........................................................................................................................................................57 Assignment Statements...........................................................................................................................................................57 Conditional (If-Else) Statements............................................................................................................................................58 Loops.......................................................................................................................................................................................59 Do-While Loops.........................................................................................................................................................59 While Loops................................................................................................................................................................60 For Loops....................................................................................................................................................................60 Traditional For Loops.....................................................................................................................................61 List or Set Iteration For Loops........................................................................................................................61 SOQL For Loops............................................................................................................................................62 SOQL and SOSL Queries......................................................................................................................................................64 Working with SOQL and SOSL Query Results.........................................................................................................65 Working with SOQL Aggregate Functions................................................................................................................66 Working with Very Large SOQL Queries..................................................................................................................67 Using SOQL Queries That Return One Record........................................................................................................69 Improving Performance by Not Searching on Null Values.........................................................................................69 Understanding Foreign Key and Parent-Child Relationship SOQL Queries.............................................................70 Working with Polymorphic Relationships in SOQL Queries.....................................................................................70 Using Apex Variables in SOQL and SOSL Queries...................................................................................................71 Querying All Records with a SOQL Statement..........................................................................................................73 Locking Statements.................................................................................................................................................................73 Locking in a SOQL For Loop....................................................................................................................................74 Avoiding Deadlocks....................................................................................................................................................74 Transaction Control................................................................................................................................................................74 Exception Statements..............................................................................................................................................................75 Throw Statements.......................................................................................................................................................75 Try-Catch-Finally Statements.....................................................................................................................................75 Chapter 3: Invoking Apex...................................................................................................................77 Triggers...................................................................................................................................................................................78 Bulk Triggers...............................................................................................................................................................79 Trigger Syntax.............................................................................................................................................................79 Trigger Context Variables...........................................................................................................................................80 Context Variable Considerations.................................................................................................................................82 Common Bulk Trigger Idioms....................................................................................................................................83 Using Maps and Sets in Bulk Triggers............................................................................................................83 Correlating Records with Query Results in Bulk Triggers..............................................................................84 Using Triggers to Insert or Update Records with Unique Fields.....................................................................84 ii Table of Contents Defining Triggers........................................................................................................................................................84 Triggers and Merge Statements..................................................................................................................................86 Triggers and Recovered Records.................................................................................................................................87 Triggers and Order of Execution.................................................................................................................................87 Operations that Don't Invoke Triggers.......................................................................................................................89 Entity and Field Considerations in Triggers...............................................................................................................90 Trigger Exceptions......................................................................................................................................................91 Trigger and Bulk Request Best Practices.....................................................................................................................92 Apex Scheduler........................................................................................................................................................................93 Anonymous Blocks..................................................................................................................................................................98 Apex in AJAX.........................................................................................................................................................................99 Chapter 4: Classes, Objects, and Interfaces........................................................................................101 Understanding Classes..........................................................................................................................................................102 Defining Apex Classes...............................................................................................................................................102 Extended Class Example...........................................................................................................................................103 Declaring Class Variables..........................................................................................................................................106 Defining Class Methods............................................................................................................................................107 Using Constructors....................................................................................................................................................109 Access Modifiers........................................................................................................................................................111 Static and Instance.....................................................................................................................................................112 Using Static Methods and Variables..............................................................................................................112 Using Instance Methods and Variables..........................................................................................................113 Using Initialization Code...............................................................................................................................114 Apex Properties.........................................................................................................................................................115 Interfaces and Extending Classes..........................................................................................................................................117 Custom Iterators........................................................................................................................................................118 Keywords...............................................................................................................................................................................120 Using the final Keyword............................................................................................................................................121 Using the instanceof Keyword...................................................................................................................................121 Using the super Keyword...........................................................................................................................................121 Using the this Keyword.............................................................................................................................................122 Using the transient Keyword.....................................................................................................................................123 Using the with sharing or without sharing Keywords................................................................................................124 Annotations...........................................................................................................................................................................126 Deprecated Annotation.............................................................................................................................................127 Future Annotation.....................................................................................................................................................127 IsTest Annotation.....................................................................................................................................................128 ReadOnly Annotation...............................................................................................................................................131 RemoteAction Annotation........................................................................................................................................132 Apex REST Annotations..........................................................................................................................................132 RestResource Annotation..............................................................................................................................133 HttpDelete Annotation.................................................................................................................................133 HttpGet Annotation......................................................................................................................................134 HttpPatch Annotation...................................................................................................................................134 iii Table of Contents HttpPost Annotation.....................................................................................................................................134 HttpPut Annotation......................................................................................................................................134 Classes and Casting...............................................................................................................................................................134 Classes and Collections.............................................................................................................................................136 Collection Casting.....................................................................................................................................................136 Differences Between Apex Classes and Java Classes.............................................................................................................136 Class Definition Creation......................................................................................................................................................137 Naming Conventions.................................................................................................................................................139 Name Shadowing......................................................................................................................................................139 Class Security........................................................................................................................................................................139 Enforcing Object and Field Permissions...............................................................................................................................140 Namespace Prefix..................................................................................................................................................................141 Using Namespaces When Invoking Methods...........................................................................................................142 Namespace, Class, and Variable Name Precedence...................................................................................................142 Type Resolution and System Namespace for Types..................................................................................................143 Version Settings....................................................................................................................................................................143 Setting the Salesforce API Version for Classes and Triggers....................................................................................144 Setting Package Versions for Apex Classes and Triggers..........................................................................................145 Chapter 5: Testing Apex...................................................................................................................146 Understanding Testing in Apex............................................................................................................................................147 Why Test Apex?........................................................................................................................................................147 What to Test in Apex................................................................................................................................................147 Unit Testing Apex.................................................................................................................................................................148 Isolation of Test Data from Organization Data in Unit Tests..................................................................................149 Using the runAs Method...........................................................................................................................................150 Using Limits, startTest, and stopTest.......................................................................................................................151 Adding SOSL Queries to Unit Tests........................................................................................................................152 Running Unit Test Methods.................................................................................................................................................153 Testing Best Practices...........................................................................................................................................................156 Testing Example...................................................................................................................................................................157 Chapter 6: Dynamic Apex.................................................................................................................162 Understanding Apex Describe Information..........................................................................................................................163 Dynamic SOQL....................................................................................................................................................................172 Dynamic SOSL.....................................................................................................................................................................172 Dynamic DML.....................................................................................................................................................................173 Chapter 7: Batch Apex......................................................................................................................176 Using Batch Apex..................................................................................................................................................................177 Understanding Apex Managed Sharing................................................................................................................................186 Understanding Sharing..............................................................................................................................................186 Sharing a Record Using Apex....................................................................................................................................188 Recalculating Apex Managed Sharing.......................................................................................................................193 Chapter 8: Debugging Apex..............................................................................................................198 iv Table of Contents Understanding the Debug Log..............................................................................................................................................199 Working with Logs in the Developer Console..........................................................................................................203 Debugging Apex API Calls.......................................................................................................................................212 Handling Uncaught Exceptions............................................................................................................................................213 Understanding Execution Governors and Limits..................................................................................................................214 Using Governor Limit Email Warnings...............................................................................................................................219 Chapter 9: Developing Apex in Managed Packages............................................................................220 Package Versions...................................................................................................................................................................221 Deprecating Apex..................................................................................................................................................................221 Behavior in Package Versions................................................................................................................................................222 Versioning Apex Code Behavior...............................................................................................................................222 Apex Code Items that Are Not Versioned................................................................................................................223 Testing Behavior in Package Versions.......................................................................................................................224 Chapter 10: Exposing Apex Methods as SOAP Web Services..............................................................226 WebService Methods............................................................................................................................................................227 Exposing Data with WebService Methods................................................................................................................227 Considerations for Using the WebService Keyword..................................................................................................227 Overloading Web Service Methods...........................................................................................................................229 Chapter 11: Exposing Apex Classes as REST Web Services................................................................230 Introduction to Apex REST..................................................................................................................................................231 Apex REST Annotations......................................................................................................................................................231 Apex REST Methods............................................................................................................................................................231 Exposing Data with Apex REST Web Service Methods......................................................................................................236 Apex REST Code Samples...................................................................................................................................................237 Apex REST Basic Code Sample...............................................................................................................................237 Apex REST Code Sample Using RestRequest.........................................................................................................238 Chapter 12: Invoking Callouts Using Apex........................................................................................240 Adding Remote Site Settings................................................................................................................................................241 SOAP Services: Defining a Class from a WSDL Document...............................................................................................241 Invoking an External Service.....................................................................................................................................242 HTTP Header Support.............................................................................................................................................242 Supported WSDL Features.......................................................................................................................................243 Understanding the Generated Code..........................................................................................................................246 Testing Web Service Callouts...................................................................................................................................248 Considerations Using WSDLs..................................................................................................................................250 Mapping Headers..........................................................................................................................................250 Understanding Runtime Events.....................................................................................................................251 Understanding Unsupported Characters in Variable Names.........................................................................251 Debugging Classes Generated from WSDL Files.........................................................................................251 Invoking HTTP Callouts......................................................................................................................................................251 Using Certificates..................................................................................................................................................................252 Generating Certificates..............................................................................................................................................252 v Table of Contents Using Certificates with SOAP Services.....................................................................................................................253 Using Certificates with HTTP Requests...................................................................................................................254 Callout Limits and Limitations.............................................................................................................................................254 Chapter 13: Reference.......................................................................................................................256 Apex Data Manipulation Language (DML) Operations......................................................................................................257 ConvertLead Operation............................................................................................................................................258 Delete Operation.......................................................................................................................................................261 Insert Operation........................................................................................................................................................263 Merge Statement.......................................................................................................................................................266 Undelete Operation...................................................................................................................................................267 Update Operation......................................................................................................................................................269 Upsert Operation.......................................................................................................................................................271 sObjects That Do Not Support DML Operations....................................................................................................275 sObjects That Cannot Be Used Together in DML Operations................................................................................276 Bulk DML Exception Handling...............................................................................................................................278 Apex Standard Classes and Methods....................................................................................................................................278 Apex Primitive Methods...........................................................................................................................................279 Blob Methods................................................................................................................................................279 Boolean Methods...........................................................................................................................................280 Date Methods................................................................................................................................................281 Datetime Methods.........................................................................................................................................284 Decimal Methods..........................................................................................................................................289 Double Methods............................................................................................................................................295 ID Methods...................................................................................................................................................296 Integer Methods............................................................................................................................................298 Long Methods...............................................................................................................................................299 String Methods..............................................................................................................................................300 Time Methods...............................................................................................................................................323 Apex Collection Methods..........................................................................................................................................324 List Methods.................................................................................................................................................325 Map Methods................................................................................................................................................331 Set Methods...................................................................................................................................................335 Enum Methods.........................................................................................................................................................339 Apex sObject Methods..............................................................................................................................................340 Schema Methods...........................................................................................................................................340 sObject Methods............................................................................................................................................344 sObject Describe Result Methods.................................................................................................................349 Describe Field Result Methods.....................................................................................................................353 Schema.FieldSet Methods.............................................................................................................................361 Custom Settings Methods.............................................................................................................................364 Apex System Methods...............................................................................................................................................372 ApexPages Methods......................................................................................................................................373 Approval Methods.........................................................................................................................................374 Database Methods.........................................................................................................................................375 vi Table of Contents JSON Support...............................................................................................................................................389 Limits Methods.............................................................................................................................................406 Math Methods...............................................................................................................................................409 MultiStaticResourceCalloutMock Methods..................................................................................................414 Apex REST...................................................................................................................................................414 Search Methods.............................................................................................................................................420 StaticResourceCalloutMock Methods...........................................................................................................420 System Methods............................................................................................................................................421 Test Methods.................................................................................................................................................432 TimeZone Methods......................................................................................................................................437 Type Methods...............................................................................................................................................438 URL Methods...............................................................................................................................................442 UserInfo Methods..........................................................................................................................................445 Version Methods...........................................................................................................................................447 Using Exception Methods.........................................................................................................................................449 Apex Classes..........................................................................................................................................................................451 Apex Email Classes...................................................................................................................................................452 Outbound Email............................................................................................................................................452 Inbound Email...............................................................................................................................................464 Exception Class.........................................................................................................................................................469 Constructing an Exception............................................................................................................................469 Using Exception Variables.............................................................................................................................471 Visualforce Classes.....................................................................................................................................................471 Action Class...................................................................................................................................................471 Dynamic Component Methods and Properties.............................................................................................472 IdeaStandardController Class........................................................................................................................473 IdeaStandardSetController Class...................................................................................................................476 KnowledgeArticleVersionStandardController Class......................................................................................480 Message Class................................................................................................................................................484 PageReference Class......................................................................................................................................485 SelectOption Class.........................................................................................................................................490 StandardController Class...............................................................................................................................492 StandardSetController Class..........................................................................................................................494 Flow.Interview Class.................................................................................................................................................497 Pattern and Matcher Classes.....................................................................................................................................498 Using Patterns and Matchers.........................................................................................................................498 Using Regions................................................................................................................................................499 Using Match Operations...............................................................................................................................499 Using Bounds................................................................................................................................................500 Understanding Capturing Groups.................................................................................................................500 Pattern and Matcher Example.......................................................................................................................500 Pattern Methods............................................................................................................................................501 Matcher Methods..........................................................................................................................................503 HTTP (RESTful) Services Classes...........................................................................................................................508 HTTP Classes...............................................................................................................................................509 vii Table of Contents Crypto Class..................................................................................................................................................519 EncodingUtil Class........................................................................................................................................525 XML Classes.............................................................................................................................................................526 XmlStream Classes........................................................................................................................................526 DOM Classes................................................................................................................................................533 Apex Approval Processing Classes............................................................................................................................539 Apex Approval Processing Example..............................................................................................................539 ProcessRequest Class.....................................................................................................................................540 ProcessResult Class........................................................................................................................................541 ProcessSubmitRequest Class.........................................................................................................................541 ProcessWorkitemRequest Class....................................................................................................................542 Apex Support Classes................................................................................................................................................543 BusinessHours Class......................................................................................................................................543 Cases Class....................................................................................................................................................545 Apex Community Classes..........................................................................................................................................545 Answers Class................................................................................................................................................546 Ideas Class.....................................................................................................................................................547 Knowledge Management Publishing Service Class...................................................................................................550 Site Class...................................................................................................................................................................554 Cookie Class..............................................................................................................................................................559 Network Class...........................................................................................................................................................561 Connect in Apex—Developer Preview......................................................................................................................562 Apex Interfaces......................................................................................................................................................................562 Auth.RegistrationHandler Interface..........................................................................................................................564 Comparable Interface................................................................................................................................................567 HttpCalloutMock Interface.......................................................................................................................................569 InstallHandler Interface.............................................................................................................................................569 Support.EmailTemplateSelector Interface................................................................................................................571 Site.UrlRewriter Interface..........................................................................................................................................572 Using the Process.Plugin Interface............................................................................................................................579 Process.Plugin Interface.................................................................................................................................580 Process.PluginRequest Class..........................................................................................................................581 Process.PluginResult Class............................................................................................................................582 Process.PluginDescribeResult Class..............................................................................................................582 Process.Plugin Data Type Conversions.........................................................................................................585 Sample Process.Plugin Implementation for Lead Conversion.......................................................................585 UninstallHandler Interface........................................................................................................................................591 WebServiceMock Interface.......................................................................................................................................593 Chapter 14: Deploying Apex.............................................................................................................594 Using Change Sets To Deploy Apex.....................................................................................................................................595 Using the Force.com IDE to Deploy Apex...........................................................................................................................595 Using the Force.com Migration Tool....................................................................................................................................596 Understanding deploy................................................................................................................................................597 Understanding retrieveCode......................................................................................................................................599 viii Table of Contents Understanding runTests()..........................................................................................................................................600 Using SOAP API to Deploy Apex........................................................................................................................................601 Appendices......................................................................................................................................602 Appendix A: Shipping Invoice Example....................................................................................602 Shipping Invoice Example Walk-Through...............................................................................................................602 Shipping Invoice Example Code...............................................................................................................................605 Appendix B: Reserved Keywords..............................................................................................614 Appendix C: Security Tips for Apex and Visualforce Development.............................................616 Cross Site Scripting (XSS)........................................................................................................................................616 Unescaped Output and Formulas in Visualforce Pages.............................................................................................618 Cross-Site Request Forgery (CSRF).........................................................................................................................619 SOQL Injection........................................................................................................................................................620 Data Access Control..................................................................................................................................................622 Appendix D: SOAP API and SOAP Headers for Apex..............................................................624 ApexTestQueueItem.................................................................................................................................................625 ApexTestResult.........................................................................................................................................................626 compileAndTest()......................................................................................................................................................629 CompileAndTestRequest..............................................................................................................................630 CompileAndTestResult.................................................................................................................................631 compileClasses()........................................................................................................................................................633 compileTriggers()......................................................................................................................................................634 executeanonymous()..................................................................................................................................................634 ExecuteAnonymousResult.............................................................................................................................635 runTests()..................................................................................................................................................................635 RunTestsRequest...........................................................................................................................................637 RunTestsResult..............................................................................................................................................637 DebuggingHeader.....................................................................................................................................................641 PackageVersionHeader..............................................................................................................................................642 Glossary...........................................................................................................................................644 Index...............................................................................................................................................662 ix Table of Contents x Chapter 1 Introducing Apex In this chapter ... • • • What is Apex? What's New? Apex Quick Start Salesforce.com has changed the way organizations do business by moving enterprise applications that were traditionally client-server-based into an on-demand, multitenant Web environment, the Force.com platform. This environment allows organizations to run and customize applications, such as Salesforce Automation and Service & Support, and build new custom applications based on particular business needs. While many customization options are available through the Salesforce user interface, such as the ability to define new fields, objects, workflow, and approval processes, developers can also use the SOAP API to issue data manipulation commands such as delete(), update() or upsert(), from client-side programs. These client-side programs, typically written in Java, JavaScript, .NET, or other programming languages grant organizations more flexibility in their customizations. However, because the controlling logic for these client-side programs is not located on Force.com platform servers, they are restricted by: • • The performance costs of making multiple round-trips to the salesforce.com site to accomplish common business transactions The cost and complexity of hosting server code, such as Java or .NET, in a secure and robust environment To address these issues, and to revolutionize the way that developers create on-demand applications, salesforce.com introduces Force.com Apex code, the first multitenant, on-demand programming language for developers interested in building the next generation of business applications. • • • What is Apex?—more about when to use Apex, the development process, and some limitations What's new in this Apex release? Apex Quick Start—delve straight into the code and write your first Apex class and trigger 1 Figure 1: You can add Apex to most system events. such as INSERT. including button clicks. including: • Data manipulation language (DML) calls. Apex enables developers to add business logic to most system events. Apex code can be initiated by Web service requests and from triggers on objects. and DELETE.com platform idioms. Apex is: Integrated Apex provides built-in support for common Force. that include built-in DmlException handling • Inline Salesforce Object Query Language (SOQL) and Salesforce Object Search Language (SOSL) queries that return lists of sObject records • Looping that allows for bulk processing of multiple records at a time • Locking syntax that prevents record update conflicts • Custom public Force.com platform server in conjunction with calls to the Force. object-oriented programming language that allows developers to execute flow and transaction control statements on the Force. and Visualforce pages. As a language. UPDATE.Introducing Apex What is Apex? What is Apex? Apex is a strongly typed.com API.com API calls that can be built from stored Apex methods 2 . related record updates. Using syntax that looks like Java and acts like database stored procedures. object. Apex produces code that is both succinct and easy to write. Easy to test Apex provides built-in support for unit test creation and execution.Introducing Apex How Does Apex Work? • Warnings and errors issued when a user tries to edit or delete a custom object or field that is referenced by Apex Easy to use Apex is based on familiar Java idioms. and so on. and which parts of your code could be more efficient.com platform.com ensures that Apex code always work as expected by executing all unit tests stored in metadata prior to any platform upgrades. Hosted Apex is interpreted. and Database. Apex runs in a multitenant environment.com API. Because the compiled code is stored as metadata in the platform. Versioned You can save your Apex code against different versions of the Force. Note that like other database stored procedures.com platform server. it uses syntax and semantics that are easy to understand and encourage efficient use of the Force. It fails quickly at compile time if any references are invalid. Automatically upgradeable Apex never needs to be rewritten when other parts of the Force. Multitenant aware Like the rest of the Force. and controlled entirely by the Force. including test results that indicate how much code is covered.com platform. it always gets automatically upgraded with the rest of the system. How Does Apex Work? All Apex runs entirely on-demand on the Force. Apex does not attempt to provide general support for rendering elements in the user interface. Salesforce. much as developers use database stored procedures to thread together multiple transaction statements on a database server. executed. Consequently.com platform.com platform.com. Where Apex introduces new elements. and class dependencies in metadata to ensure they are not deleted while required by active Apex code. Apex is included in Unlimited Edition.com platform are upgraded. Data focused Apex is designed to thread together multiple query and DML statements into a single unit of work on the Force. the Apex runtime engine is designed to guard closely against runaway code. preventing them from monopolizing shared resources. This enables you to maintain behavior. such as variable and expression syntax. Rigorous Apex is a strongly-typed language that uses direct references to schema objects such as object and field names. as shown in the following architecture diagram: 3 . Developer Edition. and stores all custom field. block and conditional statement syntax. Any code that violate these limits fail with easy-to-understand error messages. loop syntax. object and array notation. Enterprise Edition. Consequently. Write your Apex.com platform. What is the Apex Development Process? We recommend the following process for developing Apex: 1. the platform application server first compiles the code into an abstract set of instructions that can be understood by the Apex runtime interpreter. 4. Using a Developer or Sandbox Organization There are three types of organizations where you can run your Apex: • • • A developer organization: an organization created with a Developer Edition account. A sandbox organization: an organization created on your production organization that is a copy of your production organization. perhaps by clicking a button or accessing a Visualforce page. When an end-user triggers the execution of Apex. Learn more about Apex. you can also add your classes and triggers to a Force.com AppExchange App package. 6. A production organization: an organization that has live users accessing your data. The end-user observes no differences in execution time from standard platform requests. and run entirely on the Force. Obtain a Developer Edition account. the platform application server retrieves the compiled instructions from the metadata and sends them through the runtime interpreter before returning the result.Introducing Apex What is the Apex Development Process? Figure 2: Apex is compiled. While writing Apex. Deploy your Apex to your Salesforce production organization. and then saves those instructions as metadata. once it is written and tested. 5. 2. stored. 4 . Optionally deploy your Apex to a sandbox organization and do final unit tests. 3. When a developer writes and saves Apex code to the platform. you should also be writing tests. In addition to deploying your Apex. Salesforce deactivates the New Sandbox button when an organization reaches its sandbox limit. A Developer Edition account gives you access to a free Developer Edition organization. and attachments. we recommend that you do all your development work in either a sandbox or a Developer Edition organization. but exclude all of your organization's standard and custom object records. Salesforce only displays the Refresh link for sandboxes that are eligible for refreshing. apps.com to order more sandboxes for your organization. Names with fewer characters make sandbox logins easier to type. If your newly-signed-up organization includes Apex. see “Sandbox Overview” in the online help. dashboards. Note: You cannot make changes to Apex using the Salesforce user interface in a Salesforce production organization. you must deploy your code to your organization using one of the deployment methods. this is any time after 29 days from the previous creation or refresh of that sandbox.force. Even if you already have an Enterprise or Unlimited Edition organization and a sandbox for creating Apex. 2.Introducing Apex What is the Apex Development Process? Note: Apex triggers are available in the Trial Edition of Salesforce. Tip: We recommend that you choose a name that: • • Reflects the purpose of this sandbox. you can refresh once per day. however. For information on different kinds of sandboxes. You can refresh a configuration-only sandbox once per day. they are disabled when you convert to any other edition.” Has few characters because Salesforce automatically appends the sandbox name to usernames and email addresses on user records in the sandbox environment. The refreshed copy is inactive until you activate it. price books. Instead. go to http://developer.com/join and follow the instructions to sign up for a Developer Edition account. but it can only include up to 500 MB of data. Click Refresh to replace an existing sandbox with a new copy. Creating a configuration-only sandbox can decrease the time it takes to create or refresh a sandbox from several hours to just a few minutes. documents. If necessary. such as “QA. Multiple users can log into a single developer sandbox. Just like configuration-only • 5 . 4. If you aren't already a member of the developer community. For configuration-only sandboxes (including developer sandboxes). Click Your Name > Setup > Data Management > Sandbox. • 3. but their primary purpose is to provide an environment in which changes under active development can be isolated until they’re ready to be shared. You can't develop Apex in your Salesforce production organization. For full-copy sandboxes. contact salesforce. Note that Salesforce deactivates all refresh links if you have exceeded your sandbox limit. You can only change the name when you create or refresh a sandbox. products. Developer: Developer sandboxes are special configuration-only sandboxes intended for coding and testing by a single developer. and customizations under Your Name > Setup. Creating a Sandbox Organization To create or refresh a sandbox organization: 1. we strongly recommends that you take advantage of the resources available in the developer community. Do one of the following: • Click New Sandbox. Select the type of sandbox: • Configuration Only: Configuration-only sandboxes copy all of your production organization's reports. Live users accessing the system while you're developing can destabilize your data or corrupt your application. Your existing copy of this sandbox remains available while you wait for the refresh to complete. Enter a name and description for the sandbox. documents. products. price books. If you have reduced the number of sandboxes you purchased. and discovery topics. you must choose one full sandbox to convert to a smaller sandbox. case history and opportunity history serve the same purpose for cases and opportunities. Read the warning carefully and if you agree to the removal. Warning: Activating a replacement sandbox that was created using the Refresh link completely deletes the sandbox it is refreshing. you will be required to match your sandboxes to the number of sandboxes that you purchased. but you still have more sandboxes of a specific type than allowed. and attachments. documents. and opportunity history to copy. Please read the warning carefully. The default value is 0 days. Instead. You can refresh a developer sandbox once per day. if you have two full sandboxes but purchased only one. and whether or not to copy Chatter data. If you are refreshing an existing sandbox. Tip: Try to limit changes in your production organization while the sandbox copy proceeds. Full: Full sandboxes copy your entire production organization and all its data. messages. you cannot refresh your full sandbox as a full sandbox. the newly created sandbox is now ready for use. You will receive a notification email when your newly created or refreshed sandbox has completed copying. Chatter data includes feeds. For example. the radio button usually preselects the sandbox type corresponding to the sandbox you are refreshing. and attachments.Introducing Apex What is the Apex Development Process? • sandboxes. apps. which is enough for many development and testing tasks. hours. the radio button preselects Configuration Only. some radio buttons may be disabled if you have already created the number of sandboxes of that sandbox type allowed for your organization. including standard and custom object records. dashboards. 7. if you refresh a configuration-only sandbox. Click the Activate link next to the sandbox you wish to activate. and customizations under Your Name > Setup. in 30–day increments. To delete your existing sandbox and activate the new one: a. you will receive a notification email. Object history is the field history tracking of custom and most standard objects. depending on which type of sandbox you have available. choose how much object history. enter the acknowledgment text at the prompt and click the Activate button. Developer sandboxes are limited to 10 MB of test or sample data. or even days. b. including any application or data changes you have made. If you are refreshing an existing sandbox. This will take you to a page warning of removal of your existing sandbox. and press the Activate link only if you have no 6 . 6. developer sandboxes copy all application and configuration information to the sandbox. For a full sandbox. You can copy from 0 to 180 days of history. For example. such as configuration-only or developer sandbox. When the activation process is complete. All configuration and data in the prior sandbox copy will be lost. depending on the size of your organization and whether you are creating a full copy or configuration-only copy. The process may take several minutes. an additional step is required to complete the sandbox copy process. Click Start Copy. Note: Configuration-only and developer sandboxes copy all of your production organization's reports. c. 5. Return to the sandbox list by logging into your production organization and navigating to Your Name > Setup > Data Management > Sandbox. Because they copy much less data. Whether refreshing an existing sandbox or creating a new one. The new sandbox must be activated. but exclude all of your organization's standard and custom object records. Decreasing the amount of data you copy can significantly speed up sandbox copy time. You can refresh a full-copy sandbox every 29 days. If you are creating a new sandbox. case history. creating these sandbox types can substantially decrease the time it takes to create or refresh a sandbox. salesforce.com. or your refreshed sandbox is activated. and trigger logic to update the prices in open invoices. but not passwords. Newly created sandboxes have the default email deliverability setting System email only. Force. REST Web services. You can log into the sandbox at test.test. you'll first build a database model for keeping track of merchandise. if your username for your production organization is user1@acme. we've added a final tutorial to use Adobe Flash Builder for Force.com Workbook: Get Started Building Your First App in the Cloud Beginning programmers A set of ten 30-minute tutorials that introduce various Force.com Workbook tutorials are centered around building a very simple warehouse management system. You'll continue by adding business logic: validation rules to ensure that there is enough stock. and then the start of a simple store front. If you'd like to develop offline and integrate with the app. unit tests. you can click the link in the notification email to access your sandbox. For example. scheduled Apex. you'll create a user interface to display a product inventory to staff.sandbox_name to your Salesforce username. Your production organization and its data will not be affected. then your username for a sandbox named “test” is user1@acme. and Visualforce controllers. Once the database and business logic are complete. These resources provide a quick introduction to Apex and include best practices for Apex development.com Workbook: HTML | PDF Apex Workbook Beginning programmers The Apex Workbook introduces you to the Apex programming language through a set of tutorials. 8. Once your new sandbox is complete.Introducing Apex What is the Apex Development Process? further need for the contents of the sandbox copy currently in use. Learning Apex After you have your developer account. Note: Salesforce automatically changes sandbox usernames. Apex Workbook: HTML | PDF Developer Force Apex Page Beginning and advanced programmers The Apex page on Developer Force has links to several resources including articles about the Apex programming language. workflow to update inventory when something is sold. batch Apex.com platform to add custom business logic through triggers. The Force. The System email only setting is especially useful for controlling email sent from sandboxes so that testing and development work doesn’t send test emails to your users. Force. approvals to send email notifications for large invoice values. a public website to display a product catalog.com/login.jsp by appending . You’ll learn the fundamentals of Apex and how you can use it on the Force. You'll start developing the application from the bottom up.com Cookbook Beginning and advanced programmers 7 .com. that is. there are many resources available to you for learning about Apex: Force.com platform features.com. Introducing Apex What is the Apex Development Process? This collaborative site provides many recipes for using the Web services API.com IDE provides a unified interface for building and deploying Force. The Force. developer. the IDE provides tools to accelerate Force.com platform. advanced programmers should look at: • Trigger and Bulk Request Best Practices • Advanced Apex Programming Example • Understanding Apex Describe Information • Asynchronous Execution (@future Annotation) • Batch Apex and Apex Scheduler Writing Apex You can write Apex code and tests in any of the following editing environments: • The Force.com/cookbook. This tool includes basic color-coding.com to support its users and partners but isn't considered part of our services for purposes of the salesforce.com IDE is a free resource provided by salesforce. and auto-compilation on save with error message display. developing Apex code.com Platform Architects and advanced programmers Whether you are an architect.com Training & Certification. You can read and comment on existing recipes. including source code editors.com application development.com IDE is a plug-in for the Eclipse IDE. the Development Life Cycle Guide prepares you to undertake the development and release of complex applications on the Force. Designed for developers and development teams. or submit your own recipes.com applications. In This Book (Apex Developer's Guide) Beginning programmers should look at the following: • Introducing Apex. wizards and integrated help. The Force. at developer. administrator. test execution tools. Note: The Force. Training Courses Training classes are also available from salesforce. 8 . and in particular: ◊ Documentation Conventions ◊ Core Concepts ◊ Quick Start Tutorial • • • Classes. outline view.com Master Subscription Agreement. integrated unit testing. See the website for information about installation and usage. and Interfaces Testing Apex Understanding Execution Governors and Limits In addition to the above.com programming techniques and best practices.force. and creating Visualforce pages. You can find a complete list of courses at the Training & Certification site. Objects.com Cookbook helps developers become familiar with common Force. Development Life Cycle: Enterprise Development on the Force. or manager. click Your Name > Setup > Customize. Click New. keywords. Writing Tests Testing is the key to successful long term development. • • Every trigger must have some test coverage. To facilitate the development of robust. including positive and negative cases. For more information. and are flagged with the testMethod keyword in the method definition. and then enter your code in the Body text box. You cannot save your code until it compiles without errors. that is. you should make sure that every use case of your application is covered. and click the name of the object. click the name of the object. commit no data to the database. click Your Name > Setup > Develop > Apex Classes. or use one of the API calls to deploy it. ◊ For a class. the SOAP API includes methods for compiling triggers and classes. and so on. as well as bulk and single record. click Your Name > Setup > Develop > Objects.debug are not counted as part of Apex code coverage. and uses color coding to distinguish different elements. In the Triggers related list. In addition. and any syntax errors are flagged. For more information on writing tests. This should lead to 75% or more of your code being covered by unit tests. literal strings. and is a critical component of the development process. and all of those tests must complete successfully. see Deploying Apex on page 594 and SOAP API and SOAP Headers for Apex on page 624. Calls to System. Unit tests are class methods that verify whether a particular piece of code is working properly. such as comments. click New. Instead. Unit test methods take no arguments. and then enter your code in the Body text box. your focus shouldn't be on the percentage of code that is covered. 9 . While only 75% of your Apex code must be covered by tests. test development that occurs at the same time as code development. see Testing Apex on page 146. such as Notepad. send no emails. click New. Note: You cannot make changes to Apex using the Salesforce user interface in a Salesforce production organization. Apex supports the creation and execution of unit tests. You can write your Apex code. and then enter your code in the Body text box. then either copy and paste it into your application. Tip: If you want to extend the Eclipse plug-in or develop an Apex IDE of your own. every unit test in your organization namespace is executed. while the Metadata API includes methods for deploying code to production environments. In the Triggers detail page. error-free code. The Salesforce user interface also numbers the lines in the code. Note the following. Test methods and test classes are not counted as part of Apex code coverage.Introducing Apex What is the Apex Development Process? • The Salesforce user interface. • Any text editor.com AppExchange. All classes and triggers must compile successfully. the following must be true. We strongly recommend that you use a test-driven development process. and executing test methods. ◊ ◊ ◊ ◊ When deploying to a production organization. and click Triggers. before you deploy Apex or package it for the Force. ◊ For a trigger on a custom object. • At least 75% of your Apex code must be covered by unit tests. ◊ For a trigger on a standard object. All classes and triggers are compiled when they are saved. You can also use the deploy() Metadata API call to deploy your Apex from a developer organization to a sandbox organization. a list of classes. use the Force. Adding Apex Code to a Force.com_IDE. the final step is deploying Apex to your Salesforce production organization.com IDE and the Force. see http://wiki. These copies are called sandboxes and are nearly identical to your Salesforce production organization. such as testing and training. You can specify which tests should run during package install by annotating them with @isTest(OnInstall=true). This subset of tests must pass for the package install to succeed. For more information about the Force. Sandboxes are completely isolated from your Salesforce production organization. you can deploy Apex through change sets in the Salesforce user interface. so operations you perform in your sandboxes do not affect your Salesforce production organization.com Quick Reference for Developing Packages. see http://wiki. see Using the Force.com recommends that any AppExchange package that contains Apex be a managed package.php/Force.com Migration Tool that allows you to issue these commands in a console window. For more information.com Migration Tool are free resources provided by salesforce.Introducing Apex What is the Apex Development Process? Deploying Apex to a Sandbox Organization Salesforce gives you the ability to create multiple copies of your organization in separate environments for a variety of purposes. and vice versa.com IDE to a Salesforce organization. In addition. Any Apex that is included as part of a package must have at least 75% cumulative test coverage. tests with the@isTest(OnInstall=true) annotation run when the package is installed in the installer's organization. To deploy Apex from a local project in the Force.com AppExchange App You can also include an Apex class or trigger in an app that you are creating for AppExchange.com_IDE.com IDE.com/index. use the Force. but aren't considered part of our services for purposes of the salesforce. without compromising the data and applications in your Salesforce production organization.com to support its users and partners.com IDE. When you upload your package to AppExchange.php/Force. or a namespace.developerforce. In addition. see “Developing Apex in Managed Packages” in the Salesforce online help.com IDE to a Salesforce organization. see the Force. For more information.com Master Subscription Agreement. Deploying Apex to a Salesforce Production Organization After you have finished all of your unit tests and verified that your Apex code is executing properly.com Component Deployment Wizard. For more information about the Force. Each trigger must also have some test coverage.com Migration Tool and Deploying Apex. or your can implement your own deployment code. In a development or sandbox organization. all tests are run to ensure that they run without errors. you can run the unit tests for a specific class. Also. A useful API call is runTests(). To deploy Apex from a local project in the Force. Note: The Force.com Component Deployment Wizard. salesforce.developerforce. Salesforce includes a Force. For more information about Apex in managed packages. 10 . see Deploying Apex on page 594.com/index. For more information and for additional deployment options. and the SOAP API. enable the Translation Workbench and explicitly package the individual languages used in the translated custom labels. but it is not currently meant to be a general purpose programming language. See “Custom Labels Overview” in the Salesforce online help. Salesforce provides the ability to customize the prebuilt applications to fit your organization. What are the Limitations of Apex? Apex radically changes the way that developers create on-demand business applications. efficient application interaction. or add additional functionality Create temporary files Spawn threads 11 . not just with a single record or object. Create your own custom flow control through an application. However. Visualforce. When this is the case. a Visualforce page. Perform complex validation over multiple objects. When Should I Use Apex? The Salesforce prebuilt applications provide powerful CRM functionality. your organization may have complex business processes that are unsupported by the existing functionality. the Force. or from SOAP API. These include Apex. Create email services. regardless of whether it originates in the user interface. Apex Use Apex if you want to: • • • • • • Create Web services. Define navigation patterns and data-specific rules for optimal. such as saving a record. For more information.) Attach custom logic to another operation. In addition. SOAP API Use standard SOAP API calls if you want to add functionality to a composite application that processes only one type of record at a time and does not require any transactional control (such as setting a Savepoint or rolling back changes). Create complex business processes that are not supported by workflow. Visualforce Visualforce consists of a tag-based markup language that gives developers a more powerful way of building applications and customizing the Salesforce user interface. see the SOAP API Developer's Guide. As of this release. so that it occurs whenever the operation is executed. see the Visualforce Developer's Guide. For more information. Create custom transactional logic (logic that occurs over the entire transaction.Introducing Apex When Should I Use Apex? Note: Packaging Apex classes that contain references to custom labels which have translations: To include the translations in the package.com platform includes a number of ways for advanced administrators and developers to implement custom functionality. With Visualforce you can: • • • Build wizards and other multistep processes. Apex cannot be used to: • • • • Render elements in the user interface other than error messages Change standard functionality—Apex can only prevent the functionality from happening. Convention Courier font Description In descriptions of syntax. After reviewing the basics. fields and Apex code as a managed packaged from Force. This example illustrates many more features of the language. You can either create these on your own. you may want to learn some of the core concepts of Apex. Note: The Hello World and the shipping invoice samples require custom fields and objects.com AppExchange. or download the objects.000 records. See Also: Understanding Execution Governors and Limits Trigger and Bulk Request Best Practices What's New? Review the Winter ’13 Release Notes for a summary of new and changed Apex features in Winter ’13. which is a shared resource used by all other organizations. trigger. Documentation Typographical Conventions Apex and Visualforce documentation uses the following typographical conventions. You cannot assume that your code only works on a single record at a time. the execution of Apex is bound by governor limits that ensure no single Apex execution impacts the overall service of Salesforce. monospace font indicates items that you should type as shown. see wiki. Because Apex is very similar to Java. Apex Quick Start Once you have a Developer Edition or sandbox organization. and unit test. All Apex requests return a collection that contains from 1 to 50. In addition. you are ready to write your first Apex program—a very simple class. except for brackets.developerforce. there is a more complex shipping invoice example that you can also walk through.php/Documentation. This means all Apex code is limited by the number of operations (such as DML or SOQL) that it can perform within one process.Introducing Apex What's New? Tip: All Apex code runs on the Force. you may recognize much of the functionality. To guarantee consistent performance and scalability. you must implement programming patterns that take bulk processing into account. Therefore. For example: Public class HelloWorld 12 . you may run into the governor limits.com/index.com platform. For more information. If you do not. In descriptions of syntax. In the following example. } Bold Courier font In code samples and syntax descriptions. specifying value is optional: data_type variable_name [ = value]. | In descriptions of syntax. You supply the actual value. less-than and greater-than symbols (< >) are typed exactly as shown. .] | [= new Set<data_type{value [. In the following example. value2.Phone}"/> </apex:pageBlockTable> <> {} In descriptions of syntax. the pipe sign means “or”. you can create a new unpopulated set in one of two ways..Introducing Apex Understanding Apex Core Concepts Convention Italics Description In descriptions of syntax. In the following example. <apex:pageBlockTable value="{!account.Contacts}" var="contact"> <apex:column value="{!contact. You can do one of the following (not all).] }.FirstName}! </apex:page> [] In descriptions of syntax.] | . Understanding Apex Core Concepts Apex code typically contains many things that you might be familiar with from other programming languages: 13 . anything included in brackets is optional.Name}"/> <apex:column value="{!contact.MailingCity}"/> <apex:column value="{!contact. or you can populate the set: Set<data_type> set_name [= new Set<data_type>(). three values need to be supplied: datatype variable_name [ = value]. bold courier font emphasizes a portion of the code or syntax. such as a class name or variable value: public static class YourClassHere { . braces ({ }) are typed exactly as shown.. If the syntax is bold and italic. italics represent variables. . the text represents a code element that needs a value supplied by you. <apex:page> Hello {!$User. unless you manually update the version setting. You cannot save the same class or trigger against different versions.Introducing Apex Understanding Apex Core Concepts Figure 3: Programming elements in Apex The section describes the basic functionality of Apex. but which version of Apex as well. For more information about using version settings with managed packages.com API against which to save your Apex class or trigger. see “About Package Versions” in the Salesforce online help. select a package from the list of available packages. as well as some of the core concepts. You can also use version settings to associate a class or trigger with a particular version of a managed package that is installed in your organization from AppExchange. This setting indicates not only the version of SOAP API to use. Using Version Settings In the Salesforce user interface you can specify a version of the Salesforce. Every class or trigger name must be unique. To add an installed managed package to the settings list. 14 . This version of the managed package will continue to be used by the class or trigger if later versions of the managed package are installed. You can change the version after saving. The list is only displayed if you have an installed managed package that is not already associated with the class or trigger. Note // that no value has been assigned to it. objects and sObjects. the values of the object's fields can be changed in the method. as well as reserved keywords. that is. all primitive data type arguments. methods or classes. This means that any changes to the arguments exist only within the scope of the method. In Apex. as well as more advanced types such as lists. You can also assign values later. such as assigning a value to a variable Conditional (if-else) Loops: ◊ Do-while ◊ While ◊ For • • • • • Locking Data Manipulation Language (DML) Transaction Control Method Invoking Exception Handling 15 .Introducing Apex Understanding Apex Core Concepts Naming Variables. the passed-in argument still references the same object as before the method call and can't be changed to point to another object. which is also referred to as an sObject. Use the following syntax when declaring variables: datatype variable_name [ = value]. // and has the value of 0. Variables are declared with a name and a data type. test. You must end all statements with a semi-colon. Tip: Note that the semi-colon at the end of the above is not optional. This means that when the method returns. such as sObjects.com platform. are also passed into methods by value. Apex data types include basic types such as Integer. The following are examples of variable declarations: // The following variable has the data type of Integer with the name Count. Account MyAcct = new Account(). such as Integer or String. Using Statements A statement is any coded instruction that performs an action. maps. These include words that are part of Apex and the Force. However. Integer Count = 0. Methods and Classes You cannot use any of the Apex reserved keywords when naming variables. Non-primitive data type arguments. you must declare the data type of a variable when you first refer to it. and Boolean. Decimal Total. or account. Using Variables and Expressions Apex is a strongly-typed language. You can assign a value to a variable when you declare it. such as list. // The following variable has the data type of Decimal with the name Total. // The following variable is an account. the changes to the arguments are lost. In Apex. Date. When the method returns. are passed into methods by value. statements must end with a semicolon and can be one of the following types: • • • Assignment. debug(2).]}.debug(4). unordered elements. For example: if (true) { System. For more information. } In cases where a block consists of only one statement. System. The first index position in a list is always 0. or other collections. such as Integers. You can have duplicate elements in a list. It can contain primitive data types. For example: if (true) System. Use a list when the sequence of elements is important.] | [=new List<datatype>{value [. value2.Introducing Apex Understanding Apex Core Concepts A block is a series of statements that are grouped together with curly braces and can be used in any place where a single statement would be allowed. such as sObjects. Date. such as String. and so on. else System. . List<Integer> My_List = new List<Integer>().debug(1).] | . you must declare the data type of My_List as a list of Integer. .debug(2). and assigns it to the variable My_List. The following example creates a list of Integer. It can also contain more complex data types. see Lists on page 33. } else { System. To create a list: • • Use the new keyword Use the List keyword followed by the element type contained within <> characters. because Apex is strongly typed. the curly braces can be left off. Use the following syntax for creating a list: List <datatype> list_name [= new List<datatype>().debug(1). Remember. To create a set: • • Use the new keyword Use the Set keyword followed by the primitive data type contained within <> characters 16 . A set is a collection of unique. objects.debug(3). Using Collections Apex has the following types of collections: • • • Lists (arrays) Maps Sets A list is a collection of elements. System. Strings. Integer. Set<String> My_String = new Set<String>{'a'. The following example creates a map that has a data type of Integer for the key and String for the value. key2_value => value2_value. To create a map: • • Use the new keyword Use the Map keyword followed by a key-value pair.]}. 2 => 'b'. You can have duplicate values in a map. value_datatype> map_name [=new map<key_datatype. but each key must be unique. In this example. see Maps on page 40. 3 => 'c'}. Use the following syntax for creating a map: Map<key_datatype. see Sets on page 38. value_datatype> {key1_value => value1_value [. String> My_Map = new Map<Integer. The basic syntax is as follows: if (Condition){ // Do this if the condition is true } else { // Do this if the condition is not true } For more information. .] }. The values for the set are passed in using the curly braces {}. . Use a map when finding something by key matters. Keys can be any primitive data type. . Map<Integer.] | [= new Set<datatype>{value [. loops tell your application to do the same thing again and again based on a condition. 'c'}. delimited by a comma and enclosed in <> characters. as well as objects and other collections. For more information.] | .Introducing Apex Understanding Apex Core Concepts Use the following syntax for creating a set: Set<datatype> set_name [= new Set<datatype>(). see Conditional (If-Else) Statements on page 58. Using Loops While the if statement enables your application to do things based on a condition. 'b'. value_datatype>(). The following example creates a set of String. String>{1 => 'a'.] | [=new map<key_datatype. value2. the values for the map are being passed in between the curly braces {} as the map is being created. Values can include primitive data types. Apex supports the following types of loops: 17 . A map is a collection of key-value pairs. For more information.] | . Using Branching An if statement is a true-false test that enables your application to do different things based on a condition. . Select Number for the data type and click Next. A For loop enables you to more finely control the condition used with the loop. Enter Books for the plural label. In this step. Enter 16 in the length text box. Enter Book for the label. click New. 8.Introducing Apex Writing Your First Apex Class and Trigger • • • Do-while While For A Do-while loop checks the condition after the code has executed. Enter Price for the field label. Click Next to accept the default values for field-level security. For more information. 18 . Ta dah! You've now created your first custom object. 10. Click Your Name > Setup > Create > Objects and click New Custom Object. It also shows how to deploy these components to a production organization. Now let's create a custom field. you create a custom object called Book with one custom field called Price. 2. 6. In the Custom Fields & Relationships section of the Book detail page. A While loop checks the condition at the start. and click Next. 3. 7. see the Developer Edition Environment Sign Up Page. Log into your sandbox or Developer organization. See Also: Creating a Custom Object Adding an Apex Class Adding an Apex Trigger Adding a Test Class Deploying Components to Production Creating a Custom Object Prerequisites: A Salesforce account in a sandbox Unlimited or Enterprise Edition organization. Click Save. For more information about creating a sandbox organization. Writing Your First Apex Class and Trigger This step-by-step tutorial shows how to create a simple Apex class and trigger. 4. This tutorial is based on a custom object called Book that is created in the first step. 9. see “Sandbox Overview” in the Salesforce online help. Enter 2 in the decimal places text box. as well as For loops that use lists and SOQL queries as part of the condition. 11. This custom object is updated through a trigger. In addition. 1. before the code executes. or an account in a Developer organization. Apex supports traditional For loops where you set the conditions. see Loops on page 59. 5. To sign up for a free Developer organization. and is both public and static. Custom objects already have some standard fields.Price__c *= 0. Click Your Name > Setup > Develop > Apex Classes and click New. For more information. See Also: Writing Your First Apex Class and Trigger Adding an Apex Class Adding an Apex Class Prerequisites: • • A Salesforce account in a sandbox Unlimited or Enterprise Edition organization. public static void applyDiscount(Book__c[] books) { for (Book__c b :books){ b. } 19 . such as Account. a list of Book records. In the class editor. you add an Apex class that contains a method for updating the book price. 1. you don't need to create an instance of the class to access the method—you can just use the name of the class followed by a dot (.) and the name of the method. like Name and CreatedBy. For this tutorial. } } This method is called applyDiscount.9.Introducing Apex Writing Your First Apex Class and Trigger 12. Click Save.Price__c *= 0. The Book custom object In this step. enter this class definition: public class MyHelloWorld { } The previous code is the class definition to which you will be adding one method in the next step. For more information. 2. the Price field is part of our Book object and it is accessed by the Apex class you will write in the next step. or an account in a Developer organization.9. Standard objects that are provided in the Salesforce application. 3. The next section of code contains the rest of the method definition: for (Book__c b :books){ b. This indicates that it is a custom object that you created. which is assigned to the variable books. don't end with this postfix. and allow you to add other fields that are more specific to your implementation. Apex code is generally contained in classes. which means the class is available to other Apex classes and triggers. and Interfaces on page 101. This method takes one parameter. Objects. Add this method definition between the class opening and closing brackets. This class is defined as public. This method is called by the trigger that you will be adding in the next step. Notice the __c in the object name Book__c. see Classes. You’ve just created a custom object called Book. see Static and Instance on page 112. and added a custom field to that custom object. Because it is a static method. Standard fields that are provided by default in Salesforce are accessed using the same type of dot notation but without the __c. Another way to write this statement is b.com platform database. In the triggers section. 2.9. The *= operator is a shortcut.Price__c field.9. In this step. Book. which means its value will be discounted by 10%.Price__c = b. MyHelloWorld.Name. 1. 3. The statement b. takes the old value of b. All triggers run in bulk.Price__c *= 0.Introducing Apex Writing Your First Apex Class and Trigger Notice the __c after the field name Price__c. See Understanding Expression Operators on page 50. Name doesn't end with __c in Book__c.new. that is. You should now have this full class definition. In the trigger editor. Click Save to save the new class. public class MyHelloWorld { public static void applyDiscount(Book__c[] books) { for (Book__c b :books){ b. or an account in a Developer organization. you create a trigger for the Book__c custom object that calls the applyDiscount method of the MyHelloWorld class that you created in the previous step.9. Click Your Name > Setup > Create > Objects and click the name of the object you just created..applyDiscount(books). click New. The MyHelloWorld Apex class.Price__c *= 0. This code is part of the applyDiscount static method that is called by the trigger that you will create in the next step. or deleted from the Force.Price__c * 0. 4. This indicates it is a custom field that you created. Every trigger runs with a set of context variables that provide access to the records that caused the trigger to fire.9. updated. delete the default template code and enter this trigger definition: trigger HelloWorldTrigger on Book__c (before insert) { Book__c[] books = Trigger. for example. See Also: Writing Your First Apex Class and Trigger Creating a Custom Object Adding an Apex Trigger Adding an Apex Trigger Prerequisites: • • A Salesforce account in a sandbox Unlimited or Enterprise Edition organization. they process several records at once.Price__c. multiplies it by 0. and then stores the new value into the b. } } } You now have a class that contains some code which iterates over a list of books and updates the Price field for each book. A trigger is a piece of code that executes before or after records of a particular type are inserted. } The first line of code defines the trigger: trigger HelloWorldTrigger on Book__c (before insert) { 20 . For example. The test method exercises and validates the code in the trigger and class. 21 . The HelloWorldTrigger Apex trigger. including positive and negative cases. In this step. In the next step. Calls to System. or an account in a Developer organization. Test methods and test classes are not counted as part of Apex code coverage. This should lead to 75% or more of your code being covered by unit tests. It passes in the array of new books. You also run the test and verify code coverage.new. you will see why this is so and you will be able to add a test class. Trigger context variables such as Trigger.new are implicitly defined in all triggers and provide access to the records that caused the trigger to fire. and defines the events that cause it to fire. it operates on the Book__c object. Book__c[] books = Trigger. this trigger is called HelloWorldTrigger. specifies the object on which it operates.applyDiscount(books).new. MyHelloWorld. However. as well as bulk and single record. you should make sure that every use case of your application is covered. The next line in the code calls the method applyDiscount in the MyHelloWorld class. Note the following.debug are not counted as part of Apex code coverage. every unit test in your organization namespace is executed. and runs before new books are inserted into the database. Instead.new contains all the new books that are about to be inserted. Unit tests are an important part of writing code and are required. • At least 75% of your Apex code must be covered by unit tests.Introducing Apex Writing Your First Apex Class and Trigger It gives the trigger a name. ◊ ◊ ◊ ◊ When deploying to a production organization. your focus shouldn't be on the percentage of code that is covered. Trigger. The next line in the trigger creates a list of book records named books and assigns it the contents of a trigger context variable called Trigger. • • Every trigger must have some test coverage. you add a test class with one test method. All classes and triggers must compile successfully. See Also: Writing Your First Apex Class and Trigger Adding an Apex Class Adding a Test Class Adding a Test Class Prerequisites: • • A Salesforce account in a sandbox Unlimited or Enterprise Edition organization. it enables you to reach 100% code coverage for the trigger and class. Before you can deploy Apex or package it for the Force. and all of those tests must complete successfully. In this case. there is still one piece of the puzzle missing.com AppExchange. Also. the following must be true. Note: Testing is an important part of the development process. You now have all the code that is needed to update the price of all books that get inserted. While only 75% of your Apex code must be covered by tests. Price__c). Price__c=100). You can also add the @isTest annotation to individual methods. that the trigger modified: // Retrieve the new book b = [SELECT Price__c FROM Book__c WHERE Id =:b. and then logs the new price.debug('Price after trigger fired: ' + b.debug('Price before inserting new book: ' + b. Once the book is inserted. they are automatically rolled back when execution completes and you don't have to delete any test data created in the test method. The following line is the actual test. // Retrieve the new book b = [SELECT Price__c FROM Book__c WHERE Id =:b.Price__c).Price__c). This means that if any changes are made to the database.Price__c).Id]. One advantage to creating a separate class for testing as opposed to adding test methods to an existing class is that classes defined with isTest don't count against your organization limit of 3 MB for all Apex code. System. code coverage information. The System. System.Price__c). // Insert book insert b. System. the code retrieves the newly inserted book. In this case. 3. First the test method creates a new book and inserts it into the database temporarily.debug('Price after trigger fired: ' + b. // Insert book insert b. System. @isTest private class HelloWorldTestClass { static testMethod void validateHelloWorld() { Book__c b = new Book__c(Name='Behind the Cloud'. verifying that the method applyDiscount actually ran and produced the expected result: // Test that the trigger correctly updated the price System.Price__c). // Test that the trigger correctly updated the price System. see IsTest Annotation on page 128 and Understanding Execution Governors and Limits on page 214. using the ID that was initially assigned to the book when it was inserted. Click Run Test in the class page to run all the test methods in this class. b. It contains the test result details such as the number of test failures. we have only one test method. The method validateHelloWorld is defined as a testMethod. For more information.debug statement writes the value of the price in the debug log.assertEquals(90.Id]. add this test class definition.Introducing Apex Writing Your First Apex Class and Trigger 1. 22 . The Apex Test Result page appears after the test finishes execution. and then click Save. Classes defined as such can only contain test methods. } } This class is defined using the @isTest annotation. it updates the Price__c field and reduces its value by 10%. b. and a link to a downloadable log file.assertEquals(90.debug('Price before inserting new book: ' + b. When the MyHelloWorld class runs. In the class editor. Price__c=100). Book__c b = new Book__c(Name='Behind the Cloud'. Click Your Name > Setup > Develop > Apex Classes and click New. 2. 6. After a test finishes running. the call to the applyDiscount class method. but you can perform other tasks in the user interface while the test is still running and then visit this page later to check the test status. You'll see that the trigger you wrote also has 100% of its code covered. and the debug output of the price before and after the trigger. which runs the test asynchronously. By now. you can: • • Click the test to see result details. See “Change Sets Overview” in the Salesforce online help. c. Create and Upload Change Sets user permissions to create. Click Your Name > Setup > Develop > Apex Test Execution. The HelloWorldTestClass Apex test class. you deploy the Apex code and the custom object you created previously to your production organization using change sets. the first error message and the stack trace display. you want to deploy the code along with any other prerequisite components to a production organization. After the test execution completes. or upload outbound change sets. b. In the Code Coverage column.Introducing Apex Writing Your First Apex Class and Trigger 4. In this step. edit. Alternatively. a. Click Run Tests. 5. you completed all the steps necessary for having some Apex code that has been tested and that runs in your development environment. Select the class HelloWorldTestClass. Click View to see the source Apex code. The next step will show you how to do this for the code and custom object you’ve just created. you can use the Developer Console for debugging Apex code. verify the amount of code coverage. See Also: Writing Your First Apex Class and Trigger Adding an Apex Trigger Deploying Components to Production Deploying Components to Production Prerequisites: • • • • A Salesforce account in a sandbox Unlimited or Enterprise Edition organization. Click Your Name > Setup > Develop > Apex Classes. 23 . Click Calculate your organization's code coverage to see the amount of code in your organization that is covered by unit tests. after you’ve sufficiently tested your code and you’re satisfied with it. In the real world. c. See “Developer Console” in the Salesforce online help. click 100% to see the lines of code covered by unit tests. You can also run the test through the Apex Test Execution page. and then click Run. b. a. which means that you don't have to wait for the test run to finish to get the test result. You can find logging information about the trigger event. A deployment connection between the sandbox and production organizations that allows inbound change sets to be received by the production organization. Click Download and select to open the log file. if a test fails. Take a look at the list of triggers by clicking Your Name > Setup > Develop > Apex Triggers. click Add. 7. Click Save. for example. Select Apex Class from the component type drop-down list. click Continue. click Upload. Enter a name for your change set. and test class. click your change set's name. 11. you also learned how to upload the code and the custom object using Change Sets. Click Your Name > Setup > Deploy > Outbound Changesets. If you have a Developer Edition account. 6. click Continue. In the change set components section. and optionally a description. you can use other deployment methods. 1. 9. class. then select the MyHelloWorld and the HelloWorldTestClass classes from the list and click Add to Change Set. d. 5. 3. 8. b. If a splash page appears. See Also: Writing Your First Apex Class and Trigger Adding a Test Class 24 . Click View/Add Dependencies to add the dependent components. Click Deploy. Click Add To Change Set. and how to test your code. Log into your production organization. in this case production. e. Select the top checkbox to select all components. 2.com Edition organizations. c. In this tutorial. 10. HelloWorldChangeSet. deploy it in your production organization. In the change set detail section of the change set page. Enterprise. you learned how to create a custom object.Introducing Apex Writing Your First Apex Class and Trigger This procedure doesn't apply to Developer organizations since change sets are available only in Unlimited. Finally. In the change sets awaiting deployment list. In the Change Sets list. or Database. a. 4. If a splash page appears. and click Upload. After the change set upload completes. See Deploying Apex. Select the target organization. how to add an Apex trigger. click New. Click Your Name > Setup > Deploy > Inbound Change Sets. and custom data types based on system and user-provided Apex types. 25 . and conditional statements. Apex is integrated with the database—it allows you to write inline queries. Like other programming languages. Apex has a special type of loop called SOQL for loop. Apex provides expressions. and case-insensitive programming language. Unlike other languages. The following language constructs form the base parts of Apex: • • • • • • • • • • Data Types Variables Expressions Assignment Statements Conditional (If-Else) Statements Loops SOQL and SOSL Queries Locking Statements Transaction Control Exception Statements Apex is contained in either a trigger or a class. assignment. Using those language constructs. object-oriented. The Apex language constructs are building blocks that enable you to write programs in Apex. perform record locking.. see Triggers on page 78 and Classes. • • • • • • • • • • Data Types Variables Expressions Assignment Statements Conditional (If-Else) Statements Loops SOQL and SOSL Queries Locking Statements Transaction Control Exception Statements Apex is a strongly typed. Objects. and Interfaces on page 101. For more information. you can declare variables and constants of built-in data types—primitives and sObjects—enumerations.Chapter 2 Language Constructs In this chapter . Apex provides exception handling and has different types of loops. which allows for batching query results. and control transactions.. Double. Make sure that you initialize your variables to appropriate values before using them. For example: Boolean isWinner = true. sObjects. Boolean Date A value that indicates a particular day. including: ◊ A list (or array) of primitives. ID. sObject. and Interfaces on page 101) Objects created from system supplied Apex classes (see Apex Classes on page 451) Null (for the null constant. or collections (see Lists on page 33) ◊ A set of primitives (see Sets on page 38) ◊ A map from a primitive to a primitive. For example. Apex primitive data types include: Data Type Blob Description A collection of binary data stored as a single object. 26 . You can convert this datatype to String or from String using the toString and valueOf methods. Datetime. For more information. or Boolean (see Primitive Data Types on page 26) An sObject. However. Blobs can be accepted as Web service arguments. see Crypto Class on page 519. with the line number and column of the error. Date. all variables and expressions have a data type that is one of the following: • • • A primitive. Objects. false. which can be assigned to any variable) Methods can return values of any of the listed types. are initialized to null. all compile-time exceptions are returned as specific fault codes. Type checking is strictly enforced at compile time. For more information. For example. A value that can only be assigned true. Unlike Datetime values. user defined objects. such as an Account. stored in a document (the body of a document is a Blob). or sent as attachments. such as add days.Language Constructs Data Types Data Types In Apex. You cannot manipulate a Date value. Date values contain no information about time. or collection (see Maps on page 40) • • • • A typed list of values. or MyCustomObject__c (see sObject Types on page 29) A collection. All Apex variables. merely by adding a number to a Date variable. Contact. respectively. either as a generic sObject or as a specific sObject. also known as an enum (see Enums on page 44) Objects created from user-defined Apex classes (see Classes. the parser generates an error if an object field of type Integer is assigned a value of type String. Primitive Data Types Apex uses the same primitive data types as the SOAP API. objects created from Apex classes. Long. All primitive data types are passed by value. whether they’re class member variables or method variables. or return no value and be of type Void. initialize a Boolean variable to false. or null. such as an Integer. Date values must always be created with a system static method. String. see Debugging Apex on page 198. You must use the Date methods instead. 483. String s = 'The quick brown fox jumped over the lazy dog. Doubles have a minimum value of -263 and a maximum value of 263-1.648 and a maximum value of 2. All invalid ID values are rejected with a runtime exception.147.147.com record identifier. Currency fields are automatically assigned the type Decimal.Language Constructs Primitive Data Types Data Type Datetime Description A value that indicates a particular day and time. Longs have a minimum value of -263 and a maximum value of 263-1.647.14159. the scale is determined by the item from which the Decimal is created. the scale is determined by converting the number to a String and then using the number of characters after the decimal point. ID Any valid 18-character Force. Integers have a minimum value of -2. Datetime values must always be created with a system static method. For example. such as a timestamp. for a Decimal using the setScale method. Decimal A number that includes a decimal point. If you do not explicitly set the scale. merely by adding a number to a Datetime variable. For example: ID id='00300000003T2PGAA0'. Long A 64-bit number that does not include a decimal point. that is. For example: Integer i = 1. Integer A 32-bit number that does not include a decimal point. You cannot manipulate a Datetime value. If the Decimal is created from a String. the scale is based on the scale of the field returned from the query. Note that scientific notation (e) for Doubles is not supported. String Any set of characters surrounded by single quotes. You must use the Datetime methods instead. For example: Double d=3. such as add minutes. Use this datatype when you need a range of values wider than those provided by Integer. the number of decimal places. Note that if you set ID to a 15-character value. For example: Long l = 2147483648L.'. Apex automatically converts the value to its 18-character representation. If the Decimal is created from a non-decimal number. Decimal is an arbitrary precision number. 27 .483. the scale is the number of characters after the decimal point of the String. • • • If the Decimal is created as part of a query. Double A 64-bit number that includes a decimal point. Apex Strings support use of the comparison operators ==. String Methods: As in Java. In the following example. and >=. The Solution sObject field SolutionNote operates as a special type of String. If invalid HTML is entered. Conversely. See Time Methods on page 323.new[0]. \t (tab). the heap size limit is used to ensure that your Apex programs don't grow too large. \' (single quote). <=. Empty Strings and Trailing Whitespace: sObject String field values follow the same rules as in the SOAP API: they can never be empty (only null). These conventions are necessary for database storage. Strings can be manipulated with a number of standard methods. \n (line feed). and they can never include leading and trailing whitespace. Since Apex uses SOQL comparison semantics. >. } For more information. Instead. when the Solution displays on a detail page. \r (carriage return). results for Strings are collated according to the context user's locale. and can include leading and trailing whitespace (such as might be used to construct a message). when the Solution displays on a detail page. Any JavaScript used in this field is removed before the object is created or updated. and \\ (backslash). the SolutionNote field only contains HelloGoodbye: trigger t2 on Solution (before insert) { Trigger. \f (form feed). see “HTML Solutions Overview” in the Salesforce online help. <. two non-standard primitive data types cannot be used as variable or method types. Apex classes and triggers saved (compiled) using API version 15. Time A value that indicates a particular time. See String Methods for information. see Operators on page 50. \" (double quote).new[0]. !=.0 and higher produce a runtime error if you assign a String value that is too long for the field. Escape Sequences: All Strings in Apex use the same escape sequences as SOQL strings: \b (backspace). In addition. and `are not case sensitive. but do appear in system static methods: 28 . If you have HTML Solutions enabled. the SolutionNote field has H1 HTML formatting applied to it: trigger t on Solution (before insert) { Trigger. Strings in Apex can be null or empty. } In the following example.SolutionNote = '<javascript>Hello</javascript>Goodbye'. any HTML tags used in this field are verified before the object is created or updated. Time values must always be created with a system static method.SolutionNote ='<h1>hello</h1>'. Comparison Operators: Unlike Java.Language Constructs Primitive Data Types Data Type Description String size: Strings have no limit on the number of characters they can include. an error is thrown. For more information. Currency. // and a = (Account)obj. Developers can also specify initial field values with comma-separated name = value pairs when instantiating a new sObject.com. AnyType is used within the Force. The valueOf static method converts an sObject field of type AnyType to a standard primitive. but can be assigned a valid object reference with the new operator. see “SOQL and SOSL Queries” in the Force. the term sObject refers to any object that can be stored in the Force.Language Constructs sObject Types • • AnyType. you can also have the following: Object obj = s. For example: Account a = new Account().com platform database. Because sObjects work like objects. An sObject variable represents a row of data and can only be declared in Apex using the SOAP API name of the object. For example: Account a = new Account(name = 'Acme'.com platform database exclusively for sObject fields in field history tracking tables. For more information on the AnyType data type. For example: Account a = new Account(). 29 . The Currency. MyCustomObject__c co = new MyCustomObject__c(). For example: sObject s = new Account(). see Field Types in the Object Reference for Salesforce and Force. Apex allows the use of the generic sObject abstract type to represent any object. This method is for use solely within SOQL and SOSL WHERE clauses to filter against sObject currency fields. For example: // Cast the generic variable s from the example above // into a specific account and account variable a Account a = (Account)s. The sObject data type can be used in code that processes different types of sObjects. billingcity = 'San Francisco'). You can also use casting between the generic sObject type and the specific sObject type. sObject Types In this developer's guide. DML operations work on variables declared as the generic sObject data type as well as with regular sObjects. You cannot instantiate Currency in any other type of Apex. // The following generates a runtime error Contact c = (Contact)s.newInstance static method creates a literal of type Currency.com platform database. so all instances are specific sObjects. For information on accessing existing sObjects from the Force.com SOQL and SOSL Reference. Similar to the SOAP API. The new operator still requires a concrete sObject type. sObject variables are initialized to null. If you try. // This is allowed ID id = s.label_name. sObject fields can be accessed or changed with simple dot notation.generic_error.Label. Name FROM Account WHERE Name = 'Acme' LIMIT 1]. Alternatively. insert a. sObject s = [SELECT Id. // Access the account name field and assign it 'Acme' System generated fields. You can only access the value of a custom label using system.Name.com API version 27. you can use the generic sObject put and get methods.ID. For more information on custom labels. you have two different kinds of accounts: business accounts and person accounts. it is recommended that you first convert it into a specific object.com platform assigns ID values automatically when an object record is initially inserted to the database for the first time. see “Custom Labels Overview” in the Salesforce online help. If your code creates a new account using name. the Apex runtime engine generates an error.Id. a business account is created. BillingCity = 'San Francisco'). such as Account. or is assigned with a constructor. BillingCity = 'San Francisco'). See sObject Methods. a person account is created. For example: Account a = new Account(Name = 'Acme'.Name = 'Acme'. Accessing sObject Fields As in Java. If your code uses LastName.0 or earlier s. The Force. This example shows how you can access the Id field and operations that aren’t allowed on generic sObjects. For example: String errorMsg = System. // This line results in an error when you try to save using API version 26. If you use the generic sObject type instead of a specific object. Account = convertedAccount). insert a. Name FROM Account WHERE Name = 'Acme' LIMIT 1]. sObject s = [SELECT Id. You can set the Id field for Apex code saved using Salesforce.label. Note: If your organization has enabled person accounts. You cannot create a new instance of a custom label. ID id = s.name = 'Acme2'. cannot be modified. Additionally. // The following line results in an error when you try to save String x = s. For example: Account a = new Account().Id = [SELECT Id FROM Account WHERE Name = 'Acme' LIMIT 1]. such as Created By or Last Modified Date.Id. Custom Labels Custom labels are not standard sObjects. a. Account a = new Account(Name = 'Acme'. convertedAccount. 30 . you can retrieve only the Id field using dot notation.0 and later). Contact sal = new Contact(FirstName = 'Sal'.Language Constructs sObject Types Note: The ID of an sObject is a read-only value and can never be modified explicitly in Apex unless it is cleared during a clone operation. formula field values and values for other fields that are read-only for the context user cannot be changed. update convertedAccount. Account convertedAccount = (Account)s. For more information see Lists on page 33. If you want to perform operations on an sObject. List<Account> accounts. if (!records. // including a populated c.add((Contact) record). this code uses some elements that are described later in this guide: • • For information on insert and update. The ID field can be used to change the account with which the contact is associated.sObjectType) { contacts. see SOQL and SOSL Queries on page 64.account field 31 . Account a = new Account(Name = 'Acme'). FirstName.sObjectType){ leads.Language Constructs sObject Types The following example shows how you can use SOSL over a set of records to determine their object types.getSObjectType() == Contact. } else if (record. insert a. c. List<Lead> leads. FirstName. if (record. The reference field is only populated as the result of a SOQL or SOSL query (see note below).sObjectType) { accounts. Account(Id.AccountId = a. and then how the contact can be used to modify a field on the account: Note: In order to provide the most complete example. Phone. Lead(Id. sObject[] records = ((List<sObject>)results[0]).add((Lead) record). the Contact sObject has both an AccountId field of type ID.getSObjectType() == Lead. i < records. For information on SOQL and SOSL. For example.Id. // Inserting the record automatically assigns a // value to its ID field Contact c = new Contact(LastName = 'Weissman'). you can modify its fields accordingly: public class convertToCLA { List<Contact> contacts.size(). // A SOQL query accesses data for the inserted contact. For example.isEmpty()) { for (Integer i = 0. see Insert Operation on page 263 and Update Operation on page 263. and an Account field of type Account that points to the associated sObject record itself. LastName). } else if (record.getSObjectType() == Account. i++) { sObject record = records[i]. Lead. // The new contact now points at the new account insert c. LastName). } } } } } Accessing sObject Fields Through Relationships sObject records represent relationships to other records with two fields: an ID and an address that points to a representation of the associated sObject.add((Account) record). Name)]. Phone. the following Apex code shows how an account and a contact can be associated with one another. Phone. Once you have converted the generic sObject record into a Contact. while the sObject reference field can be used to access data from the account. or Account. public void convertType(Integer phoneNumber) { List<List<sObject>> results = [FIND '4155557000' IN Phone FIELDS RETURNING Contact(Id. // This updates the account name Note: The expression c.com'.Id]. If this code was called multiple times. Contact c = new Contact(Account = refAcct. Contact c = new Contact(Account = refAcct. For more information on execution limits. The platform prevents users from making the following types of modifications when those changes cause Apex code to become invalid: • • Changing a field or object name Converting from one data type to another 32 . and a parse-time exception is thrown when an invalid name is used. LastName = 'Kay'). the sObject field key can be used with insert. displays slightly different characteristics when it is read as a value than when it is modified: • When being read as a value. c. as well as any other expression that traverses a relationship. This inserts a new contact with the AccountId equal to the account with the external_id equal to ‘12345’.LastName = 'Roth'.Account. the insert fails.Account. it is not as efficient. For example: Account refAcct = new Account(externalId__c = '12345'). it could reach the execution limit for the maximum number of SOQL queries. This design allows developers to navigate multiple relationships without the tedium of having to check for null values. However.Id). If there is no such account. // To update the database. When being modified. if c. insert c. because it uses a SOQL query.Account. all sObject and field references are validated against actual object and field names. • In addition. or upsert to resolve foreign keys by external ID. then c.Name = 'salesforce.Name does yield a NullPointerException. update.Account is null. then c.Name. but does not yield a NullPointerException. In addition. the two types of records must be // updated separately update c.Language Constructs sObject Types c = [SELECT Account. the Apex parser tracks the custom objects and fields that are used.Account. Account refAcct = [SELECT Id FROM Account WHERE externalId__c='12345'].Account. // Now fields in both records can be changed through the contact c. if c.Account is null. Validating sObjects and Fields When Apex code is parsed and validated.Name FROM Contact WHERE Id = :c. // This only changes the contact's last name update c. see Understanding Execution Governors and Limits on page 214.Name evaluates to null. insert c. both in the code's syntax as well as in embedded SOQL and SOSL statements. Tip: The following code is equivalent to the code above. // Adds the integer 1 to the list at index 0 MyList. // Create a nested list List<List<Set<Integer>>> my_list_2 = new List<List<Set<Integer>>>(). field history tracking. For example: // Create an empty list of String List<String> my_list = new List<String>().clear(). However. For example: List<Integer> MyList = new List<Integer>(). For example.get(0). To declare a list. including a complete list of all supported methods. or set type within <> characters. Name FROM Account LIMIT 1000]. map. // Create a list of account records from a SOQL query List<Account> accs = [SELECT Id. the following table is a visual representation of a list of Strings: Index 0 'Red' Index 1 'Orange' Index 2 'Yellow' Index 3 'Green' Index 4 'Blue' Index 5 'Purple' The index position of the first element in a list is always 0.add(47).Language Constructs Collections • • Deleting a field or object Making certain organization-wide changes. user-defined objects. For example. A list can contain up to four levels of nested collections inside it. // Retrieves the element at index 0 MyList. see List Methods on page 325. there is a general limit on heap size.set(0. To access elements in a list. sObject. // Removes all elements from the list For more information. // Define a new list MyList. or record types Collections Apex has the following types of collections: • • • Lists Maps Sets Note: There is no limit on the number of items a collection can hold. you can have a list of lists of sets of Integers. 33 . nested list. 1). Apex objects or collections that are distinguished by their indices. use the List keyword followed by the primitive data. use the system methods provided by Apex. such as record sharing. they can be nested within one another and become multidimensional. // Adds a second element of value 47 to the end // of the list MyList. Lists A list is an ordered collection of typed primitives. Because lists can contain any collection. sObjects. For example. Defines an Integer list with memory allocated for six Integers List<Integer> ints = new Integer[6]. To reference an element of a one-dimensional list of primitives or sObjects. Description Defines an Integer list with no elements Defines an Account list with no elements List<Account> accts = new Account[]{}. Lists can be assigned values and allocated memory using literal notation. For example: Example List<Integer> ints = new Integer[0]. and another new Account object in the third position Defines the Contact list with a new list List<Contact> contacts = new List<Contact> (otherList).Language Constructs Collections Using Array Notation for One-Dimensional Lists of Primitives or sObjects When using one-dimensional lists of primitives or sObjects. For example. including a new Account object in the first position. All lists are initialized to null. the insert statement in the following block of code generates a ListException because it tries to insert a list with two references to the same sObject (a): try { // Create a list with two references to the same sObject element Account a = new Account(). new Account()}. even if it has a null ID. For example: colors[3] = 'Green'. Lists of sObjects Apex automatically generates IDs for each object in a list of sObjects when the list is successfully inserted or upserted into the database with a data manipulation language (DML) statement. Consequently. null in the second position. which is illegal. you can also follow the name of the list with the element's index position in square brackets. null. a list of sObjects cannot be inserted or upserted if it contains the same sObject more than once. Defines an Account list with memory allocated for three Accounts. This situation would imply that two IDs would need to be written to the same structure in memory. List<Account> accts = new Account[] {new Account(). you can also use more traditional array notation to declare and reference list elements. you can declare a one-dimensional list of primitives or sObjects by following the data or sObject type name with the [] characters: String[] colors = new List<String>(). 34 . and there are two custom fields. // Will not get here System. except for the Id and Name fields. 35 . For text fields. the sort algorithm uses the Unicode sort order. // Attempt to insert it. You can also create a generic instance of a list. 2. insert accs. FieldA and FieldB. an Account sObject will appear before a Contact. sorting is in ascending order and uses a sequence of comparison steps outlined in the next section. For example. sorting is in ascending order based on the value and label fields. 4. Not all steps in this sequence are necessarily carried out. they’re sorted based on the Name field and sorting stops at step 2. For sObjects. For custom types.sort method. Sorting is in ascending order for primitive data types. see Apex Data Manipulation Language (DML) Operations on page 257. Otherwise. see Comparable Interface. SelectOption elements.sort method sorts sObjects in ascending order and compares sObjects using an ordered sequence of steps that specify the labels or fields used. account A comes before account B. the first standard field used for sorting is AccountNumber. you can sort lists of primitive data types. the sort criteria and sort order depends on the implementation that you provide for the compareTo method of the Comparable interface.Language Constructs Collections Account[] accs = new Account[]{a. if the list contains two accounts named A and B respectively. you can also implement a custom sort order for sObjects by wrapping your sObject in an Apex class and implementing the Comparable Interface. Also. Custom fields. if applicable. suppose two accounts have the same name and identical standard fields.. Standard fields. if two accounts have the same name. For example. The label of the sObject type. the value of FieldA is used first for sorting. For example. if a list contains two sObjects of the same type and with unique Name values. 3. } catch (ListException e) { // But will get here } For more information on DML statements. and sObjects (standard objects and custom objects). However. For example. You can use the generic sObject data type with lists. See Default Sort Order for SelectOption for the sequence of comparison steps used for SelectOption. as shown in Custom Sort Order of sObjects.assert(false). sorting proceeds to step 3 to sort by standard fields. custom types (your Apex classes) that implement the Comparable Interface. For more information on implementing the Comparable Interface for your own classes. a}. The following is the comparison sequence used: 1. starting with the fields that come first in alphabetical order.. For SelectOption. starting with the fields that come first in alphabetical order. The Name field. List Sorting Using the List. empty fields precede non-empty fields in the sort order. The comparison starts with the first step in the sequence and ends when two sObjects are sorted using specified labels or fields. if the names are identical or the sObject doesn’t have a Name field. Default Sort Order of sObjects The List. For example. Language Constructs Collections This is an example of sorting a list of Account sObjects. This example shows how the Name field is used to place the Acme account ahead of the two sForce accounts in the list. Since there are two accounts named sForce, the Industry field is used to sort these remaining accounts because the Industry field comes before the Site field in alphabetical order. Account[] acctList = new List<Account>(); acctList.add( new Account( Name='sForce', Industry='Biotechnology', Site='Austin')); acctList.add(new Account( Name='sForce', Industry='Agriculture', Site='New York')); acctList.add(new Account( Name='Acme')); System.debug(acctList); acctList.sort(); System.assertEquals('Acme', acctList[0].Name); System.assertEquals('sForce', acctList[1].Name); System.assertEquals('Agriculture', acctList[1].Industry); System.assertEquals('sForce', acctList[2].Name); System.assertEquals('Biotechnology', acctList[2].Industry); System.debug(acctList); This example is similar to the previous one, except that it uses the Merchandise__c custom object. This example shows how the Name field is used to place the Notebooks merchandise ahead of Pens in the list. Since there are two merchandise sObjects with the Name field value of Pens, the Description field is used to sort these remaining merchandise items because the Description field comes before the Price and Total_Inventory fields in alphabetical order. Merchandise__c[] merchList = new List<Merchandise__c>(); merchList.add( new Merchandise__c( Name='Pens', Description__c='Red pens', Price__c=2, Total_Inventory__c=1000)); merchList.add( new Merchandise__c( Name='Notebooks', Description__c='Cool notebooks', Price__c=3.50, Total_Inventory__c=2000)); merchList.add( new Merchandise__c( Name='Pens', Description__c='Blue pens', Price__c=1.75, Total_Inventory__c=800)); System.debug(merchList); merchList.sort(); System.assertEquals('Notebooks', merchList[0].Name); System.assertEquals('Pens', merchList[1].Name); System.assertEquals('Blue pens', merchList[1].Description__c); System.assertEquals('Pens', merchList[2].Name); System.assertEquals('Red pens', merchList[2].Description__c); System.debug(merchList); Custom Sort Order of sObjects To implement a custom sort order for sObjects in lists, create a wrapper class for the sObject and implement the Comparable Interface. The wrapper class contains the sObject in question and implements the compareTo method, in which you specify the sort logic. 36 Language Constructs Collections This example shows how to create a wrapper class for Opportunity. The implementation of the compareTo method in this class compares two opportunities based on the Amount field—the class member variable contained in this instance, and the opportunity object passed into the method. global class OpportunityWrapper implements Comparable { public Opportunity oppy; // Constructor public OpportunityWrapper(Opportunity op) { oppy = op; } // Compare opportunities based on the opportunity amount. global Integer compareTo(Object compareTo) { // Cast argument to OpportunityWrapper OpportunityWrapper compareToOppy = (OpportunityWrapper)compareTo; // The return value of 0 indicates that both elements are equal. Integer returnValue = 0; if (oppy.Amount > compareToOppy.oppy.Amount) { // Set return value to a positive value. returnValue = 1; } else if (oppy.Amount < compareToOppy.oppy.Amount) { // Set return value to a negative value. returnValue = -1; } return returnValue; } } This example provides a test for the OpportunityWrapper class. It sorts a list of OpportunityWrapper objects and verifies that the list elements are sorted by the opportunity amount. @isTest private class OpportunityWrapperTest { static testmethod void test1() { // Add the opportunity wrapper objects to a list. OpportunityWrapper[] oppyList = new List<OpportunityWrapper>(); Date closeDate = Date.today().addDays(10); oppyList.add( new OpportunityWrapper(new Opportunity( Name='Edge Installation', CloseDate=closeDate, StageName='Prospecting', Amount=50000))); oppyList.add( new OpportunityWrapper(new Opportunity( Name='United Oil Installations', CloseDate=closeDate, StageName='Needs Analysis', Amount=100000))); oppyList.add( new OpportunityWrapper(new Opportunity( Name='Grand Hotels SLA', CloseDate=closeDate, StageName='Prospecting', Amount=25000))); // Sort the wrapper objects using the implementation of the // compareTo method. oppyList.sort(); // Verify the sort order System.assertEquals('Grand Hotels SLA', oppyList[0].oppy.Name); System.assertEquals(25000, oppyList[0].oppy.Amount); 37 Language Constructs Collections System.assertEquals('Edge Installation', oppyList[1].oppy.Name); System.assertEquals(50000, oppyList[1].oppy.Amount); System.assertEquals('United Oil Installations', oppyList[2].oppy.Name); System.assertEquals(100000, oppyList[2].oppy.Amount); // Write the sorted list contents to the debug log. System.debug(oppyList); } } Default Sort Order for SelectOption The List.sort method sorts SelectOption elements in ascending order using the value and label fields, and is based on this comparison sequence. 1. The value field is used for sorting first. 2. If two value fields have the same value or are both empty, the label field is used. Note that the disabled field is not used for sorting. For text fields, the sort algorithm uses the Unicode sort order. Also, empty fields precede non-empty fields in the sort order. In this example, a list contains three SelectOption elements. Two elements, United States and Mexico, have the same value field (‘A’). The List.sort method sorts these two elements based on the label field, and places Mexico before United States, as shown in the output. The last element in the sorted list is Canada and is sorted on its value field ‘C’, which comes after ‘A’. List<SelectOption> options = new List<SelectOption>(); options.add(new SelectOption('A','United States')); options.add(new SelectOption('C','Canada')); options.add(new SelectOption('A','Mexico')); System.debug('Before sorting: ' + options); options.sort(); System.debug('After sorting: ' + options); This is the output of the debug statements. It shows the list contents before and after the sort. DEBUG|Before sorting: (System.SelectOption[value="A", label="United States", disabled="false"], System.SelectOption[value="C", label="Canada", disabled="false"], System.SelectOption[value="A", label="Mexico", disabled="false"]) DEBUG|After sorting: (System.SelectOption[value="A", label="Mexico", disabled="false"], System.SelectOption[value="A", label="United States", disabled="false"], System.SelectOption[value="C", label="Canada", disabled="false"]) Sets A set is an unordered collection of elements that do not contain any duplicates. Set elements can be of any data type—primitive types, collections, sObjects, user-defined types, and built-in Apex types. For example, the following table represents a set of strings, that uses city names: 'San Francisco' 'New York' 'Paris' 'Tokyo' Sets can contain collections that can be nested within one another. For example, you can have a set of lists of sets of Integers. A set can contain up to four levels of nested collections inside it. 38 Language Constructs Collections To declare a set, use the Set keyword followed by the primitive data type name within <> characters. For example: new Set<String>() The following are ways to declare and populate a set: Set<String> s1 = new Set<String>{'a', 'b + c'}; // Defines a new set with two elements Set<String> s2 = new Set<String>(s1); // Defines a new set that contains the // elements of the set created in the previous step To access elements in a set, use the system methods provided by Apex. For example: Set<Integer> s = new Set<Integer>(); s.add(1); System.assert(s.contains(1)); s.remove(1); // // // // Define Add an Assert Remove a new set element to the set that the set contains an element the element from the set Uniqueness of non-primitive objects is determined by comparing the objects’ fields, except for objects of user-defined types. For example, if you try to add two accounts with the same name to a set, only one is added. // Create two accounts, a1 and a2 Account a1 = new account(name='MyAccount'); Account a2 = new account(name='MyAccount'); // Add both accounts to the new set Set<Account> accountSet = new Set<Account>{a1, a2}; // Verify that the set only contains one item System.assertEquals(accountSet.size(), 1); However, if you add a description to one of the accounts, it is considered unique: // Create two accounts, a1 and a2, and add a description to a2 Account a1 = new account(name='MyAccount'); Account a2 = new account(name='MyAccount', description='My test account'); // Add both accounts to the new set Set<Account> accountSet = new Set<Account>{a1, a2}; // Verify that the set contains two items System.assertEquals(accountSet.size(), 2); Uniqueness of objects of user-defined types is determined by the equals and hashCode methods, which you provide in your classes. For more information, including a complete list of all supported set system methods, see Set Methods on page 335. Note the following limitations on sets: • • Unlike Java, Apex developers do not need to reference the algorithm that is used to implement a set in their declarations (for example, HashSet or TreeSet). Apex uses a hash structure for all sets. A set is an unordered collection. Do not rely on the order in which set results are returned. The order of objects returned by sets may change without warning. 39 Language Constructs Collections Maps A map is a collection of key-value pairs where each unique key maps to a single value. Keys and values can be any data type—primitive types, collections, sObjects, user-defined types, and built-in Apex types. For example, the following table represents a map of countries and currencies: Country (Key) Currency (Value) 'United States' 'Dollar' 'Japan' 'Yen' 'France' 'Euro' 'England' 'Pound' 'India' 'Rupee' Map keys and values can contain any collection, and can contain nested collections. For example, you can have a map of Integers to maps, which, in turn, map Strings to lists. Map keys can contain up to only four levels of nested collections. To declare a map, use the Map keyword followed by the data types of the key and the value within <> characters. For example: Map<String, String> country_currencies = new Map<String, String>(); Map<ID, Set<String>> m = new Map<ID, Set<String>>(); Map<ID, Map<ID, Account[]>> m2 = new Map<ID, Map<ID, Account[]>>(); You can use the generic sObject data type with maps. You can also create a generic instance of a map. As with lists, you can populate map key-value pairs when the map is declared by using curly brace ({}) syntax. Within the curly braces, specify the key first, then specify the value for that key using =>. For example: Map<String, String> MyStrings = new Map<String, String>{'a' => 'b', 'c' => 'd'.toUpperCase()}; Account[] accs = new Account[5]; // Account[] is synonymous with List<Account> Map<Integer, List<Account>> m4 = new Map<Integer, List<Account>>{1 => accs}; In the first example, the value for the key a is b, and the value for the key c is d. In the second, the key 1 has the value of the list accs. This in an example of using sObjects as map keys. Map<Account, String> mapKeyExample = new Map<Account, String>{ new Account(Name='Account1') => '
[email protected]', new Account(Name='Account2') => '
[email protected]' }; To access elements in a map, use the Map methods provided by Apex. For example: Account myAcct = new Account(); //Define a new account Map<Integer, Account> m = new Map<Integer, Account>(); // Define a new map m.put(1, myAcct); // Insert a new key-value pair in the map System.assert(!m.containsKey(3)); // Assert that the map contains a key Account a = m.get(1); // Retrieve a value, given a particular key Set<Integer> s = m.keySet(); // Return a set that contains all of the keys in the map For more information, including a complete list of all supported Map methods, see Map Methods on page 331. Note the following considerations on maps: • Unlike Java, Apex developers do not need to reference the algorithm that is used to implement a map in their declarations (for example, HashMap or TreeMap). Apex uses a hash structure for all maps. 40 Language Constructs Collections • • • • Do not rely on the order in which map results are returned. The order of objects returned by maps may change without warning. Always access map elements by key. A map key can hold the null value. Adding a map entry with a key that matches an existing key in the map overwrites the existing entry with that key with the new entry. Uniqueness of map keys of user-defined types is determined by the equals and hashCode methods, which you provide in your classes. Uniqueness of all other non-primitive types is determined by comparing the objects’ fields. Maps from SObject Arrays Maps from an ID or String data type to an sObject can be initialized from a list of sObjects. The IDs of the objects (which must be non-null and distinct) are used as the keys. One common usage of this map type is for in-memory “joins” between two tables. For instance, this example loads a map of IDs and Contacts: Map<ID, Contact> m = new Map<ID, Contact>([SELECT Id, LastName FROM Contact]); In the example, the SOQL query returns a list of contacts with their Id and LastName fields. The new operator uses the list to create a map. For more information, see SOQL and SOSL Queries on page 64. Parameterized Typing Apex, in general, is a statically-typed programming language, which means users must specify the data type for a variable before that variable can be used. For example, the following is legal in Apex: Integer x = 1; The following is not legal if x has not been defined earlier: x = 1; Lists, maps and sets are parameterized in Apex: they take any data type Apex supports for them as an argument. That data type must be replaced with an actual data type upon construction of the list, map or set. For example: List<String> myList = new List<String>(); Subtyping with Parameterized Lists In Apex, if type T is a subtype of U, then List<T> would be a subtype of List<U>. For example, the following is legal: List<String> slst = new List<String> {'foo', 'bar'}; List<Object> olst = slst; Using Custom Types in Map Keys and Sets When using a custom type (your Apex class) for the map key or set elements, provide equals and hashCode methods in your class. Apex uses these two methods to determine equality and uniqueness of keys for your objects. Adding equals and hashCode Methods to Your Class To ensure that map keys of your custom type are compared correctly and their uniqueness can be determined consistently, provide an implementation of the following two methods in your class: 41 Language Constructs Collections • The equals method with this signature: public Boolean equals(Object obj) { // Your implementation } Keep in mind the following when implementing the equals method. Assuming x, y, and z are non-null instances of your class, the equals method must be: ◊ ◊ ◊ ◊ ◊ Reflexive: x.equals(x) Symmetric: x.equals(y) should return true if and only if y.equals(x) returns true Transitive: if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true Consistent: multiple invocations of x.equals(y) consistently return true or consistently return false For any non-null reference value x, x.equals(null) should return false The equals method in Apex is based on the equals method in Java. • The hashCode method with this signature: public Integer hashCode() { // Your implementation } Keep in mind the following when implementing the hashCode method. ◊ If the hashCode method is invoked on the same object more than once during execution of an Apex request, it must return the same value. ◊ If two objects are equal, based on the equals method, hashCode must return the same value. ◊ If two objects are unequal, based on the result of the equals method, it is not required that hashCode return distinct values. The hashCode method in Apex is based on the hashCode method in Java. Another benefit of providing the equals method in your class is that it simplifies comparing your objects. You will be able to use the == operator to compare objects, or the equals method. For example: // obj1 and obj2 are instances of MyClass if (obj1 == obj2) { // Do something } if (obj1.equals(obj2)) { // Do something } Sample This sample shows how to implement the equals and hashCode methods. The class that provides those methods is listed first. It also contains a constructor that takes two Integers. The second example is a code snippet that creates three objects of the class, two of which have the same values. Next, map entries are added using the pair objects as keys. The sample verifies that the map has only two entries since the entry that was added last has the same key as the first entry, and hence, overwrote it. The sample then uses the == operator, which works as expected because the class implements equals. Also, some additional map operations are performed, like checking whether the map contains certain keys, and writing all keys and values to the 42 Language Constructs Collections debug log. Finally, the sample creates a set and adds the same objects to it. It verifies that the set size is two, since only two objects out of the three are unique. public class PairNumbers { Integer x,y; public PairNumbers(Integer a, Integer b) { x=a; y=b; } public Boolean equals(Object obj) { if (obj instanceof PairNumbers) { PairNumbers p = (PairNumbers)obj; return ((x==p.x) && (y==p.y)); } return false; } public Integer hashCode() { return (31 * x) ^ y; } } This code snippet makes use of the PairNumbers class. Map<PairNumbers, String> m = new Map<PairNumbers, String>(); PairNumbers p1 = new PairNumbers(1,2); PairNumbers p2 = new PairNumbers(3,4); // Duplicate key PairNumbers p3 = new PairNumbers(1,2); m.put(p1, 'first'); m.put(p2, 'second'); m.put(p3, 'third'); // Map size is 2 because the entry with // the duplicate key overwrote the first entry. System.assertEquals(2, m.size()); // Use the == operator if (p1 == p3) { System.debug('p1 and p3 are equal.'); } // Perform some other operations System.assertEquals(true, m.containsKey(p1)); System.assertEquals(true, m.containsKey(p2)); System.assertEquals(false, m.containsKey(new PairNumbers(5,6))); for(PairNumbers pn : m.keySet()) { System.debug('Key: ' + pn); } List<String> mValues = m.values(); System.debug('m.values: ' + mValues); // Create a set Set<PairNumbers> s1 = new Set<PairNumbers>(); s1.add(p1); s1.add(p2); s1.add(p3); // Verify that we have only two elements // since the p3 is equal to p1. System.assertEquals(2, s1.size()); 43 Language Constructs Enums Iterating Collections Collections can consist of lists, sets, or maps. Modifying a collection's elements while iterating through that collection is not supported and causes an error. Do not directly add or remove elements while iterating through the collection that includes them. Adding Elements During Iteration To add elements while iterating a list, set or map, keep the new elements in a temporary list, set, or map and add them to the original after you finish iterating the collection. Removing Elements During Iteration To remove elements while iterating a list, create a new list, then copy the elements you wish to keep. Alternatively, add the elements you wish to remove to a temporary list and remove them after you finish iterating the collection. Note: The List.remove method performs linearly. Using it to remove elements has time and resource implications. To remove elements while iterating a map or set, keep the keys you wish to remove in a temporary list, then remove them after you finish iterating the collection. Enums An enum is an abstract data type with values that each take on exactly one of a finite set of identifiers that you specify. Enums are typically used to define a set of possible values that do not otherwise have a numerical order, such as the suit of a card, or a particular season of the year. Although each value corresponds to a distinct integer value, the enum hides this implementation so that you do not inadvertently misuse the values, such as using them to perform arithmetic. After you create an enum, variables, method arguments, and return types can be declared of that type. Note: Unlike Java, the enum type itself has no constructor syntax. To define an enum, use the enum keyword in your declaration and use curly braces to demarcate the list of possible values. For example, the following code creates an enum called Season: public enum Season {WINTER, SPRING, SUMMER, FALL} By creating the enum Season, you have also created a new data type called Season. You can use this new data type as you might any other data type. For example: Season e = Season.WINTER; Season m(Integer x, Season e) { If (e == Season.SUMMER) return e; //... } 44 Language Constructs Enums You can also define a class as an enum. Note that when you create an enum class you do not use the class keyword in the definition. public enum MyEnumClass { X, Y } You can use an enum in any place you can use another data type name. If you define a variable whose type is an enum, any object you assign to it must be an instance of that enum class. Any webService methods can use enum types as part of their signature. When this occurs, the associated WSDL file includes definitions for the enum and its values, which can then be used by the API client. Apex provides the following system-defined enums: • System.StatusCode This enum corresponds to the API error code that is exposed in the WSDL document for all API operations. For example: StatusCode.CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY StatusCode.INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY The full list of status codes is available in the WSDL file for your organization. For more information about accessing the WSDL file for your organization, see “Downloading Salesforce WSDLs and Client Authentication Certificates” in the Salesforce online help. • System.XmlTag: This enum returns a list of XML tags used for parsing the result XML from a webService method. For more information, see XmlStreamReader Class on page 526. • System.ApplicationReadWriteMode: This enum indicates if an organization is in 5 Minute Upgrade read-only mode during Salesforce upgrades and downtimes. For more information, see Using the System.ApplicationReadWriteMode Enum on page 429. • System.LoggingLevel: This enum is used with the system.debug method, to specify the log level for all debug calls. For more information, see System Methods on page 421. • System.RoundingMode: This enum is used by methods that perform mathematical operations to specify the rounding behavior for the operation, such as the Decimal divide method and the Double round method. For more information, see Rounding Mode on page 293. • System.SoapType: This enum is returned by the field describe result getSoapType method. For more informations, see Schema.SOAPType Enum Values on page 361. • System.DisplayType: This enum is returned by the field describe result getType method. For more information, see Schema.DisplayType Enum Values on page 357. • System.JSONToken: This enum is used for parsing JSON content. For more information, see System.JSONToken Enum on page 405. • ApexPages.Severity: 45 Language Constructs Understanding Rules of Conversion This enum specifies the severity of a Visualforce message. For more information, see ApexPages.Severity Enum on page 484. • Dom.XmlNodeType: This enum specifies the node type in a DOM document. For more information, see Node Types on page 535. Note: System-defined enums cannot be used in Web service methods. All enum values, including system enums, have common methods associated with them. For more information, see Enum Methods on page 339. You cannot add user-defined methods to enum values. Understanding Rules of Conversion In general, Apex requires you to explicitly convert one data type to another. For example, a variable of the Integer data type cannot be implicitly converted to a String. You must use the string.format method. However, a few data types can be implicitly converted, without using a method. Numbers form a hierarchy of types. Variables of lower numeric types can always be assigned to higher types without explicit conversion. The following is the hierarchy for numbers, from lowest to highest: 1. 2. 3. 4. Integer Long Double Decimal Note: Once a value has been passed from a number of a lower type to a number of a higher type, the value is converted to the higher type of number. Note that the hierarchy and implicit conversion is unlike the Java hierarchy of numbers, where the base interface number is used and implicit object conversion is never allowed. In addition to numbers, other data types can be implicitly converted. The following rules apply: • • • IDs can always be assigned to Strings. Strings can be assigned to IDs. However, at runtime, the value is checked to ensure that it is a legitimate ID. If it is not, a runtime exception is thrown. The instanceOf keyword can always be used to test whether a string is an ID. Additional Considerations for Data Types Data Types of Numeric Values Numeric values represent Integer values unless they are appended with L for a Long or with .0 for a Double or Decimal. For example, the expression Long d = 123; declares a Long variable named d and assigns it to an Integer numeric value (123), which is implicitly converted to a Long. The Integer value on the right hand side is within the range for Integers and the assignment succeeds. However, if the numeric value on the right hand side exceeds the maximum value for an Integer, you get a compilation error. In this case, the solution is to append L to the numeric value so that it represents a Long value which has a wider range, as shown in this example: Long d = 2147483648L;. 46 Language Constructs Variables Overflow of Data Type Values Arithmetic computations that produce values larger than the maximum value of the current type are said to overflow. For example, Integer i = 2147483647 + 1; yields a value of –2147483648 because 2147483647 is the maximum value for an Integer, so adding one to it wraps the value around to the minimum negative value for Integers, –2147483648. If arithmetic computations generate results larger than the maximum value for the current type, the end result will be incorrect because the computed values that are larger than the maximum will overflow. For example, the expression Long MillsPerYear = 365 * 24 * 60 * 60 * 1000; results in an incorrect result because the products of Integers on the right hand side are larger than the maximum Integer value and they overflow. As a result, the final product isn't the expected one. You can avoid this by ensuring that the type of numeric values or variables you are using in arithmetic operations are large enough to hold the results. In this example, append L to numeric values to make them Long so the intermediate products will be Long as well and no overflow occurs. The following example shows how to correctly compute the amount of milliseconds in a year by multiplying Long numeric values. Long MillsPerYear = 365L * 24L * 60L * 60L * 1000L; Long ExpectedValue = 31536000000L; System.assertEquals(MillsPerYear, ExpectedValue); Loss of Fractions in Divisions When dividing numeric Integer or Long values, the fractional portion of the result, if any, is removed before performing any implicit conversions to a Double or Decimal. For example, Double d = 5/3; returns 1.0 because the actual result (1.666...) is an Integer and is rounded to 1 before being implicitly converted to a Double. To preserve the fractional value, ensure that you are using Double or Decimal numeric values in the division. For example, Double d = 5.0/3.0; returns 1.6666666666666667 because 5.0 and 3.0 represent Double values, which results in the quotient being a Double as well and no fractional value is lost. Variables Local variables are declared with Java-style syntax. For example: Integer i = 0; String str; Account a; Account[] accts; Set<String> s; Map<ID, Account> m; As with Java, multiple variables can be declared and initialized in a single statement, using comma separation. For example: Integer i, j, k; All variables allow null as a value and are initialized to null if they are not assigned another value. For instance, in the following example, i, and k are assigned values, while j is set to null because it is not assigned: Integer i = 0, j, k = 1; Variables can be defined at any point in a block, and take on scope from that point forward. Sub-blocks cannot redefine a variable name that has already been used in a parent block, but parallel blocks can reuse a variable name. For example: Integer i; { 47 Language Constructs Case Sensitivity // Integer i; } This declaration is not allowed for (Integer j = 0; j < 10; j++); for (Integer j = 0; j < 10; j++); Case Sensitivity To avoid confusion with case-insensitive SOQL and SOSL queries, Apex is also case-insensitive. This means: • Variable and method names are case insensitive. For example: Integer I; //Integer i; This would be an error. • References to object and field names are case insensitive. For example: Account a1; ACCOUNT a2; • SOQL and SOSL statements are case insensitive. For example: Account[] accts = [sELect ID From ACCouNT where nAme = 'fred']; Also note that Apex uses the same filtering semantics as SOQL, which is the basis for comparisons in the SOAP API and the Salesforce user interface. The use of these semantics can lead to some interesting behavior. For example, if an end user generates a report based on a filter for values that come before 'm' in the alphabet (that is, values < 'm'), null fields are returned in the result. The rationale for this behavior is that users typically think of a field without a value as just a “space” character, rather than its actual “null” value. Consequently, in Apex, the following expressions all evaluate to true: String s; System.assert('a' == 'A'); System.assert(s < 'b'); System.assert(!(s > 'b')); Note: Although s < 'b' evaluates to true in the example above, 'b.'compareTo(s) generates an error because you are trying to compare a letter to a null value. Constants Constants can be defined using the final keyword, which means that the variable can be assigned at most once, either in the declaration itself, or with a static initializer method if the constant is defined in a class. For example: public class myCls { static final Integer PRIVATE_INT_CONST; static final Integer PRIVATE_INT_CONST2 = 200; public static Integer calculate() { return 2 + 7; } static { 48 This type of expression yields a query result. set. and method invocations that evaluates to a single value. including: ◊ The ID of an sObject in a list (see Lists) ◊ A set of child records associated with an sObject (for example. one-dimensional list positions. see Using the final Keyword on page 121. operators. an expression is always one of the following types: • A literal expression. For example: Integer i myList[3] myContact.oldName • Any sObject field reference that is not an L-value. much like SOQL and SOSL queries. including variables. 49 .name myRenamingClass. This section provides an overview of expressions in Apex and contains the following: • • • • • Understanding Expressions Understanding Expression Operators Understanding Operator Precedence Extending sObject and List Expressions Using Comments Understanding Expressions An expression is a construct made up of variables. and method invocations that evaluates to a single value. Expressions An expression is a construct made up of variables. Integer>() myRenamingClass(string oldName. For example: 1 + 1 • A new sObject. } } For more information. and most sObject or Apex object field references. list. the set of contacts associated with a particular account).Language Constructs Expressions PRIVATE_INT_CONST = calculate(). In Apex. For example: new new new new new new new Account(<field_initializers>) Integer[<n>] Account[]{<elements>} List<Account>() Set<String>{} Map<String. operators. Apex object. string newName) • Any value that can act as the left-hand of an assignment operator (L-values). or map. a Boolean. Name FROM Account WHERE Name ='Acme']. For example: Account[] aa = [SELECT Id. Multiplication assignment operator (Right associative). Note that x and y must be Integers or Doubles. • A static or instance method invocation. For example: System. and cannot be null. For information. x and y cannot be null. y)). Understanding Expression Operators Expressions can also be joined to one another with operators to create compound expressions. Otherwise. Lead]. Apex supports the following operators: Operator = Syntax x = y Description Assignment operator (Right associative). Note: • • This operator exhibits “short-circuiting” behavior. Subtracts the value of y from the original value of x and then reassigns the new value to x. Divides the original value of x with the value of y and then reassigns the new value to x. x and y cannot be null. allowing for on-the-fly evaluation in Apex. List<List<SObject>> searchList = [FIND 'map*' IN ALL FIELDS RETURNING Account (Id. Division assignment operator (Right associative). Note that x and y must be Integers or Doubles. x and y cannot be null. Note that x and y must be Integers or Doubles. OR assignment operator (Right associative). += x += y *= x *= y -= x -= y /= x /= y |= x |= y 50 . Integer i = [SELECT COUNT() FROM Contact WHERE LastName ='Weissman']. or a combination. Adds the value of y to the original value of x and then reassigns the new value to x. Subtraction assignment operator (Right associative). If x. x is assigned the value of true. See + for additional information.Language Constructs Understanding Expression Operators • A SOQL or SOSL query surrounded by square brackets. Opportunity. Multiplies the value of y with the original value of x and then reassigns the new value to x. and y. Note that the data type of x must match the data type of y. or a combination. Contact. Name). or a combination. Addition assignment operator (Right associative). x and y cannot be null. see SOQL and SOSL Queries on page 64.assert(true) myRenamingClass. a Boolean.replaceNames() changePoint(new Point(x. then x remains false. Assigns the value of y to the L-value x. x and y cannot be null. are both false. which means y is evaluated only if x is false. a Boolean. a Boolean. This value is then reassigned to x. is true. Note: • • This operator exhibits “short-circuiting” behavior. and y. This operator acts as a short-hand for if-then-else statements. x and y cannot be null. Otherwise z is the result. Otherwise the expression evaluates to true. Bitwise shift right unsigned assignment operator. a Boolean. and y. Otherwise. 51 . which means y is evaluated only if x is false. then the expression evaluates to true. This value is then reassigned to x. Shifts each bit in x to the right by y bits so that the low order bits are lost. x and y cannot be null. and y. a Boolean. are both true. which means y is evaluated only if x is true. which means y is evaluated only if x is true. Shifts each bit in x to the left by y bits so that the high order bits are lost. Shifts each bit in x to the right by y bits so that the low order bits are lost. are both false. then x remains true. Note: • • • && has precedence over || >>= x >>= y >>>= x >>>= y ? : x ? y : z && x && y This operator exhibits “short-circuiting” behavior. If x. x and y cannot be null. y is the result. || x || y OR logical operator (Left associative). and the new left bits are set to 0 for positive values of y and 1 for negative values of y. a Boolean. x is assigned the value of false. AND logical operator (Left associative). and the new left bits are set to 0 for all values of y. Otherwise the expression evaluates to false. This value is then reassigned to x. Note: • • • && has precedence over || This operator exhibits “short-circuiting” behavior. If x. If x. a Boolean. If x. Note that x cannot be null.Language Constructs Understanding Expression Operators Operator &= Syntax x &= y Description AND assignment operator (Right associative). are both true. Ternary operator (Right associative). a Boolean. and the new right bits are set to 0. <<= x <<= y Bitwise shift left assignment operator. Bitwise shift right signed assignment operator. then the expression evaluates to false. Less than operator. The result is that Apex developers must use == for equality tests in the main body of the Apex code. • • • • === x === y Exact equality operator. not reference equality. the expression evaluates to false. the expression evaluates to true. or Datetimes. Apex does not support tri-state Boolean logic. If x and y reference the exact same location in memory. If x is less than y. a runtime error results. Note: • Unlike other database stored procedures. every field must have the same value for == to evaluate to true. Although Apex and SOQL and SOSL are strongly linked. the expression evaluates to true. If the value of x equals the value of y. the expression evaluates to true. Otherwise. they must reference the same type of object. x or y can be the literal null. and = for equality in SOQL and SOSL queries. and the comparison of any two values can never result in null. For records. Note that this operator only works for sObjects or collections (such as a Map or list). The comparison of any two values can never result in null. the String value is validated and treated as an ID. Otherwise. the expression is false. and not ==. == performs a deep check of all sObject field values before returning its result. == in Apex compares object value equality. Note: • Unlike Java. Likewise for collections.Language Constructs Understanding Expression Operators Operator == Syntax x == y Description Equality operator. Otherwise. If x and y are IDs. < x < y • • • • 52 . Consequently: ◊ String comparison using == is case insensitive ◊ ID comparison using == is case sensitive. the expression evaluates to false. Dates. Otherwise. and does not distinguish between 15-character and 18-character formats • For sObjects and sObject arrays. SOQL and SOSL use = for their equality operator. Doubles. A non-null String or ID value is always greater than a null value. and user-defined types. The designers of Apex deemed it more valuable to maintain this paradigm than to force developers to learn a new assignment operator. For an Apex object (such as an Exception or instantiation of a class) the exact equality operator is the same as the equality operator. built-in Apex types. the expression evaluates to false. If x or y equal null and are Integers. If x or y is an ID and the other value is a String. this unfortunate syntax discrepancy exists because most modern languages use = for assignment and == for equality. the expression evaluates to false. Note: • • • The comparison of any two values can never result in null. Doubles. A non-null String or ID value is always greater than a null value. <= x <= y Less than or equal to operator. If x is greater than or equal to y. x and y cannot be Booleans. the expression evaluates to false. If x and y are IDs. or Datetimes. If x or y equal null and are Integers. Otherwise.Language Constructs Understanding Expression Operators Operator Syntax Description • • x and y cannot be Booleans. If x and y are IDs. The comparison of two strings is performed according to the locale of the context user. the String value is validated and treated as an ID. a runtime error results. or Datetimes. Note: • • • • • • • The comparison of any two values can never result in null. the expression is false. or Datetimes. Otherwise. they must reference the same type of object. the expression evaluates to true. the expression evaluates to true. Otherwise. >= x >= y Greater than or equal to operator. The comparison of two strings is performed according to the locale of the context user. > x > y Greater than operator. Doubles. If x is less than or equal to y. A non-null String or ID value is always greater than a null value. Otherwise. the expression evaluates to false. Otherwise. Doubles. x and y cannot be Booleans. a runtime error results. the expression is false. The comparison of two strings is performed according to the locale of the context user. the expression is false. the expression evaluates to true. Dates. A non-null String or ID value is always greater than a null value. If x is greater than y. If x or y equal null and are Integers. Note: • • • • • • • The comparison of any two values can never result in null. If x or y is an ID and the other value is a String. Dates. If x or y is an ID and the other value is a String. 53 . they must reference the same type of object. the String value is validated and treated as an ID. If x or y equal null and are Integers. Dates. the expression evaluates to true. • If x is a Datetime and y is an Integer or Double.Language Constructs Understanding Expression Operators Operator Syntax Description • • • • If x and y are IDs. x and y cannot be Booleans. != x != y Inequality operator. Otherwise. != in Apex compares object value equality. + x + y - x . adds the value of x to the value of y. with the fractional portion corresponding to a portion of a day. For records. != performs a deep check of all sObject field values before returning its result. not reference equality. the result is a Double. For sObjects and sObject arrays. they must reference the same type of object. or an Apex object (such as an Exception or instantiation of a class). • If x is a Date and y is an Integer. If x and y do not reference the exact same location in memory. returns a new Date that is incremented by the specified number of days. the expression evaluates to true. collections (such as a Map or list). returns a new Date that is decremented by the specified number of days. If x or y is an ID and the other value is a String. If the value of x does not equal the value of y. Subtraction operator. a runtime error results. • If x is a String and y is a String or any other type of non-null argument. Note that this operator only works for sObjects. • If x is a Date and y is an Integer. the expression evaluates to false. the result is a Double. The comparison of two strings is performed according to the locale of the context user. != evaluates to true if the records have different values for any field.y 54 . Adds the value of x to the value of y according to the following rules: • If x and y are Integers or Doubles. Otherwise. concatenates y to the end of x. Note: • • • • • Unlike Java. !== x !== y Exact inequality operator. Subtracts the value of y from the value of x according to the following rules: • If x and y are Integers or Doubles. x or y can be the literal null. The comparison of any two values can never result in null. Otherwise. If a Double is used. If a Double is used. subtracts the value of x from the value of y. the String value is validated and treated as an ID. Addition operator. returns a new Date that is incremented by the specified number of days. the expression evaluates to false. If postfixed (x--). Note that the positive equivalent + is also syntactically valid.Language Constructs Understanding Expression Operators Operator Syntax Description • If x is a Datetime and y is an Integer or Double. a variable of a numeric type. an Integer or Double. by -1. returns a new Date that is decremented by the specified number of days. the expression evaluates to the value of x after the decrement. / x / y ! !x - -x ++ x++ ++x -- x---x & x & y | x | y ^ x ^ y ^= x ^= y << x << y >> x >> y >>> x >>> y 55 . This operator is not valid for types Long or Integer. If prefixed (--x). Exclusive ORs each bit in x with the corresponding bit in y so that the result bit is set to 1 if exactly one of the bits is set to 1 and the other bit is set to 0. the expression evaluates to the value of x before the decrement. an Integer or Double. the expression evaluates to the value of x before the increment. Adds 1 to the value of x. a variable of a numeric type. This operator is not valid for types Long or Integer. and false becomes true. Bitwise shift left operator. Logical complement operator. and the new left bits are set to 0 for all values of y. but does not have a mathematical effect. with y. Unary negation operator. Bitwise OR operator. so that true becomes false. ORs each bit in x with the corresponding bit in y so that the result bit is set to 1 if at least one of the bits is set to 1. the result is a Double. Exclusive ORs each bit in x with the corresponding bit in y so that the result bit is set to 1 if exactly one of the bits is set to 1 and the other bit is set to 0. and the new left bits are set to 0 for positive values of y and 1 for negative values of y. Note that if a double is used. Bitwise exclusive OR operator. Multiplies x. Division operator. Inverts the value of a Boolean. an Integer or Double. If prefixed (++x). Increment operator. Bitwise AND operator. and the new right bits are set to 0. Bitwise shift right unsigned operator. If postfixed (x++). the result is a Double. Divides x. another Integer or Double. with the fractional portion corresponding to a portion of a day. * x * y Multiplication operator. Shifts each bit in x to the left by y bits so that the high order bits are lost. Multiplies the value of x. Bitwise exclusive OR operator. Bitwise shift right signed operator. Shifts each bit in x to the right by y bits so that the low order bits are lost. Decrement operator. the expression evaluates to the value of x after the increment. Shifts each bit in x to the right by y bits so that the low order bits are lost. by y. ANDs each bit in x with the corresponding bit in y so that the result bit is set to 1 if both of the bits are set to 1. Note that if a double is used. another Integer or Double. Subtracts 1 from the value of x. In the following example.Name.Name. reference tests Comparisons: equal and not-equal Logical AND Logical OR Assignment operators == != && || = += -= *= /= &= Extending sObject and List Expressions As in Java. The list is populated by the SOQL statement {new Account(name='Acme')}. new Account[] generates a list. In the above. sObject and list expressions can be extended with method references and list expressions. Item 0. The name of the sObject in the list is accessed. Integer acctNameLength = new Account[]{new Account(Name='Acme')}[0]. Elevates the precedence of an expression x so that it is evaluated first in a compound expression. a name that has been shifted to lower case is returned. followed by the method returning the length name.toLowerCase(). 56 . In the following example. a new variable containing the length of the new account name is assigned to acctNameLength. is then accessed by the next part of the string [0]. type cast and object creation Multiplication and division Addition and subtraction Greater-than and less-than comparisons.length().Language Constructs Understanding Operator Precedence Operator () Syntax (x) Description Parentheses. Understanding Operator Precedence Apex uses the following operator precedence rules: Precedence 1 2 3 4 5 6 7 8 9 Operators {} () ++ -! -x +x (type) new * / + < <= > >= instanceof Description Grouping and prefix increments and decrements Unary negation. the first item in the list. to form new expressions. String nameChange = [SELECT Name FROM Account][0]. respectively.length(). Account[] accts = [SELECT Id FROM Account]. insert the record. use //. For example: Integer i = 1. it is now possible to // create a new contact that is related to it 57 . For example: ints[0] = 1. All characters on the same line to the right of the // are ignored by the parser. // This comment is ignored by the parser • To create a multiline comment. [LValue] = [[inline_soql_query]]. BillingCity = 'San Francisco'). • An sObject field reference that the context user has permission to edit. This code is invalid because // createdDate is read-only! // Since the account a has been inserted. For example: Integer i = 1. For example: Account a = new Account(Name = 'Acme'.today(). */ Assignment Statements An assignment statement is any statement that places a value into a variable. In the forms above. accts[0]. • A de-referenced list element. For example: Integer i = 1. // Fields also must be writeable for the context user // a.Name = 'Acme'.CreatedDate = System. [LValue] stands for any expression that can be placed on the left side of an assignment operator. Account a = new Account(). insert a. These include: • A simple variable.Language Constructs Using Comments Using Comments Both single and multiline comments are supported in Apex code: • To create a single line comment. // IDs cannot be set prior to an insert call // a. // Instead. The system automatically assigns it an ID. /* This comment can wrap over multiple lines without getting interpreted by the parser. use /* and */ to demarcate the beginning and end of the comment block. generally in one of the following two forms: [LValue] = [new_value_expression].Id = '00300000003T2PGAA0'. and --. Account b. is equivalent to: Integer x.Language Constructs Conditional (If-Else) Statements Contact c = new Contact(LastName = 'Roth'. else sign = -1. System. 'Acme').Name == 'Acme'). Conditional (If-Else) Statements The conditional statement in Apex works similarly to Java: if ([Boolean_condition]) // Statement 1 else // Statement 2 The else portion is always optional. 'Acme'). // These asserts should now be true. sign. a[0]. For example: Account a = new Account(). a. For example: Integer x. sign. } else { sign = -1.assertEquals(c[0]. and always groups with the closest if. *=. other valid assignment operators include +=.Name = 'Acme'. two lists can point at the same value in memory.Name.Name. b = a.Account.add(a). // Notice that you can write to the account name directly through the contact c. System. /=. // Your code if (x <= 0) if (x == 0) sign = 0.assertEquals(b.Name = 'Acme'.assert(b[0]. System. Account = a). Account[] b = a. } } 58 . // Your code if (x <= 0) { if (x == 0) { sign = 0. Account[] c = new Account[]{}. c.com'. You can reference the data // originally allocated to account a through account b and account list c. |=. In addition to =. &=.Name = 'salesforce. ++. See Understanding Expression Operators on page 50. Assignment is always done by reference. For example: Account[] a = new Account[]{new Account()}. Similarly. Language Constructs Loops Repeated else if statements are also allowed. do { System. the Apex do-while loop does not check the Boolean condition statement until after the first loop is executed. As in Java. } while (count < 11). for (variable : array_or_set) statement. As an example. 59 . } else if (place == 2) { medal_color = 'silver'.10 into the debug log: Integer count = 1. Consequently. while (Boolean_condition) statement. skips to the next iteration of the loop Do-While Loops The Apex do-while loop repeatedly executes a block of code as long as a particular Boolean condition remains true. count++. the following code outputs the numbers 1 . } else { medal_color = null. for (initialization. For example: if (place == 1) { medal_color = 'gold'. All loops allow for loop control structures: • • break. for (variable : [inline_soql_query]) statement. exits the entire loop continue. Its syntax is: do { code_block } while (condition).debug(count). Note: Curly braces ({}) are always required around a code_block. Boolean_exit_condition. } else if (place == 3) { medal_color = 'bronze'. the code block always runs at least once. increment) statement. } Loops Apex supports the following five types of procedural loops: • • • • • do {statement} while (Boolean_condition). • The SOQL for loop: for (variable : [soql_query]) { code_block } or for (variable_list : [soql_query]) { code_block } 60 . while (count < 11) { System. increment_stmt) { code_block } • The list or set iteration for loop: for (variable : list_or_set) { code_block } where variable must be of the same primitive or sObject type as list_or_set. } For Loops Apex supports three variations of the for loop: • The traditional for loop: for (init_stmt. Consequently.Language Constructs While Loops While Loops The Apex while loop repeatedly executes a block of code as long as a particular Boolean condition remains true. the following code outputs the numbers 1 . Its syntax is: while (condition) { code_block } Note: Curly braces ({}) are required around a code_block only if the block contains more than one statement. As an example.10 into the debug log: Integer count = 1. it is possible for the code block to never execute. the while loop checks the Boolean condition statement before the first loop is executed. Unlike do-while. exit_condition. count++.debug(count). 6.debug(i). the Apex runtime engine performs the following steps. Its syntax is: for (init_stmt. and runs the code_block for each value. 7. 3.10 into the debug log. the following code outputs the numbers 1 . 2. Execute the increment_stmt statement. 10}. As an example. For example. is included to demonstrate the syntax: for (Integer i = 0. } List or Set Iteration For Loops The list or set iteration for loop iterates over all the elements in a list or set. 2. } 61 . increment_stmt) { code_block } When executing this type of for loop. j. exit_condition. in order: 1. 5. the following code outputs the numbers 1 . i++) { System. 3. 9. Perform the exit_condition check. Note that multiple variables can be declared and/or initialized in this statement. the Apex runtime engine assigns variable to each element in list_or_set. the loop exits. 4. Return to Step 2. Traditional For Loops The traditional for loop in Apex corresponds to the traditional syntax used in Java and other languages. Its syntax is: for (variable : list_or_set) { code_block } where variable must be of the same primitive or sObject type as list_or_set. the loop continues. i < 10.Language Constructs For Loops Both variable and variable_list must be of the same sObject type as is returned by the soql_query. Note: Curly braces ({}) are required around a code_block only if the block contains more than one statement. Each is discussed further in the sections that follow. Execute the init_stmt component of the loop. When executing this type of for loop. j = 0. for (Integer i : myInts) { System. If false.debug(i+1). Note that an additional initialization variable. 5. 8. 4. If true.10 to the debug log: Integer[] myInts = new Integer[]{1. Execute the code_block. but is grossly inefficient if you want to use data manipulation language (DML) statements within the for loop body. the [soql_query] statement can refer to code expressions in their WHERE clauses using the : syntax. While the standard queries discussed in SOQL and SOSL Queries can retrieve either the count of a query or a number of object records. For example: String s = 'Acme'. The syntax of a SOQL for loop is either: for (variable : [soql_query]) { code_block } or for (variable_list : [soql_query]) { code_block } Both variable and variable_list must be of the same type as the sObjects that are returned by the soql_query. A runtime exception occurs if you use a query containing an aggregate function that returns more than 2000 rows in a for loop. 62 . SOQL For Loop Formats SOQL for loops can process records one at a time using a single sObject variable. Developers should always use a SOQL for loop to process query results that return many records. // Loop through the list and update the Name field for(Account a : accs){ a. it is easy to understand and use.Name = 'Oracle'. SOQL For Loops Versus Standard SOQL Queries SOQL for loops differ from standard SOQL statements because of the method they use to retrieve sObjects. Name from Account where Name LIKE :(s+'%')]) { // Your code } The following example combines creating a list from a SOQL query. with the DML update method. SOQL for loops retrieve all sObjects. Note that queries including an aggregate function don't support queryMore. Consequently. As in standard SOQL queries. // Create a list of account records from a SOQL query List<Account> accs = [SELECT Id.Language Constructs For Loops SOQL For Loops SOQL for loops iterate over all of the sObject records returned by a SOQL query. using efficient chunking with calls to the query and queryMore methods of the SOAP API. to avoid the limit on heap size. Each DML statement ends up processing only one sObject at a time. or in batches of 200 sObjects at a time using an sObject list: • The single sObject format executes the for loop's <code_block> once per sObject record. } // Update the database update accs. Name FROM Account WHERE Name = 'Siebel']. for (Account a : [SELECT Id. for (Contact c : returnedAccount. This exception is sometimes thrown when accessing a large set of child records of a retrieved sObject inside the loop.000 records at a time. // Do some other processing } • 63 . as follows. // Since a single batch can hold up to 100 records and. For example. or when getting the size of such a record set. When using the sObject list format. but is the optimal choice if you need to use DML statements within the for loop body. it is possible to encounter runtime limit errors. } System. or deleting more than one record per returned record in an sObject list for loop. // The single sObject format executes the for loop once per returned record Integer i = 0.Language Constructs For Loops • The sObject list format executes the for loop's <code_block> once per list of 200 sObjects. for (Account[] tmp : [SELECT Id FROM Account WHERE Name = 'yyy']) { j = tmp. continue skips to the next list of sObjects. Consequently. Consequently.assert(i == 3). new Account(Name = 'yyy')}. and sObject list for loops process records in batches of 200. use a for loop to iterate over the child records. Each DML statement can bulk process a list of sObjects at a time. Note: • • The break and continue keywords can be used in both types of inline query for loop formats.Contacts) { count++. i++. // only three records should have been returned.rollback(sp). } System. the loop executed three times // The sObject list format executes the for loop once per returned batch // of records i = 0. // Since there were three accounts named 'yyy' in the // database. insert new Account[]{new Account(Name = 'yyy').assert(i == 1). Integer j. the following code illustrates the difference between the two types of SOQL query for loops: // Create a savepoint because the data should not be committed to the database Savepoint sp = Database. it is a little more difficult to understand and use. for (Account tmp : [SELECT Id FROM Account WHERE Name = 'yyy']) { i++. You might get a QueryException in a SOQL for loop with the message Aggregate query has too many rows for direct assignment. use FOR loop. the // loop should have executed only once // Revert the database to the original state Database. Integer count=0.size(). To avoid getting this exception. new Account(Name = 'yyy'). DML statements can only process up to 10. if you are inserting. See Understanding Execution Governors and Limits on page 214.setSavepoint(). // The list should have contained the three accounts // named 'yyy' System.assert(j == 3). updating. LastName = 'Yoyce'. and leads that begin with the phrase map: List<List<SObject>> searchList = [FIND 'map*' IN ALL FIELDS RETURNING Account (Id.FirstName = 'James'. You can also operate on the results using standard arithmetic: Integer j = 5 * [SELECT COUNT() FROM Account]. or an Integer for count method queries. a single sObject. The result lists are always returned in the same order as they were specified in the SOSL query. c. which will need to be set. The count method can be used to return the number of rows returned by a query. Name FROM Account WHERE Name = 'Acme']. 64 .isEmpty()) { // Execute commands } You can also create new objects from SOQL queries on existing ones. you could retrieve a list of accounts that are named Acme: List<Account> aa = [SELECT Id. The following example returns the total number of contacts with the last name of Weissman: Integer i = [SELECT COUNT() FROM Contact WHERE LastName = 'Weissman']. see the Salesforce SOQL and SOSL Reference Guide. Opportunity. From this list. SOQL Statements SOQL statements evaluate to a list of sObjects. Note that the newly created object contains null values for its fields. Name). SOSL Statements SOSL statements evaluate to a list of lists of sObjects. For example. you can access individual elements: if (!aa. you can return a list of accounts. where each list contains the search results for a particular sObject type. For a full description of SOQL query syntax.Language Constructs SOQL and SOSL Queries SOQL and SOSL Queries You can evaluate Salesforce Object Query Language (SOQL) or Salesforce Object Search Language (SOSL) statements on-the-fly in Apex by surrounding the statement in square brackets. Lead]. opportunities. The following example creates a new contact for the first account with the number of employees greater than 10: Contact c = new Contact(Account = [SELECT Name FROM Account WHERE NumberOfEmployees > 10 LIMIT 1]). For example. If a SOSL query does not return any records for a specified sObject type. c. Contact. the search results include an empty list for that sObject. contacts. Opportunity. after Id. you can create arrays for each object returned: Account [] accounts = ((List<Account>)searchList[0]). Contact. a SOQL or SOSL query always returns data as complete records. the value of the FIND clause is demarcated with braces. 65 .AnnualRevenue. Name). Account acc = [SELECT Id FROM Account WHERE Name = 'Singha' LIMIT 1]. Note that Name has been added as part of the select statement.Language Constructs Working with SOQL and SOSL Query Results Note: The syntax of the FIND clause in Apex differs from the syntax of the FIND clause in the SOAP API: • In Apex. For example: FIND {map*} IN ALL FIELDS RETURNING Account (Id. Lead • In the Force. Opportunity. Lead [] leads = ((List<Lead>)searchList[3]). Consequently. Working with SOQL and SOSL Query Results SOQL and SOSL queries only return data for sObject fields that are selected in the original query. you must dereference the field in order to access it. Account acc = [SELECT Id FROM Account WHERE Name = 'Singha' LIMIT 1]. Name FROM Account WHERE Name = 'Singha' LIMIT 1]. If you try to access a field that was not selected in the SOQL or SOSL query (other than ID). For a full description of SOSL query syntax. The following is the same code example rewritten so it does not produce a runtime error. see the Salesforce SOQL and SOSL Reference Guide. Opportunity [] opportunities = ((List<Opportunity>)searchList[2]). For example: FIND 'map*' IN ALL FIELDS RETURNING Account (Id. the value of the FIND clause is demarcated with single quotes. // When only one result is returned in a SOQL query.AnnualRevenue. insert new Account(Name = 'Singha'). The following code example causes a runtime error: insert new Account(Name = 'Singha'). you receive a runtime error. even if the field contains a value in the database. accesses the first account record in the list. Lead From searchList.com API. Double rev2 = [SELECT AnnualRevenue FROM Account WHERE Name = 'Acme' LIMIT 1]. Contact [] contacts = ((List<Contact>)searchList[1]). and then dereferences the record's AnnualRevenue field: Double rev = [SELECT AnnualRevenue FROM Account WHERE Name = 'Acme'][0].Name.Name. it is not necessary // to include the list's index. this code retrieves an sObject list from the database with a SOQL query. // Note that name is not selected String name = [SELECT Id FROM Account WHERE Name = 'Singha' LIMIT 1]. Name). For example. // Note that name is now selected String name = [SELECT Id. Even if only one sObject field is selected. Contact. the values of the formula fields themselves cannot be changed in Apex. For example.get('aver'). not just the number of rows returned by the query.get('expr0')). where i denotes the order of the aggregated fields with no explicit aliases. For example. Also note that sObject fields that contain formulas return the value of the field at the time the SOQL or SOSL query was issued. Note: Queries that include aggregate functions are subject to the same governor limits as other SOQL queries for the total number of records returned. Working with SOQL Aggregate Functions Aggregate functions in SOQL. is when the query returns an Integer as the result of a COUNT operation: Integer i = [SELECT COUNT() FROM Account].debug('Campaign ID' + ar.debug('Average amount' + ar.get('CampaignId')). AVG(Amount) FROM Opportunity GROUP BY CampaignId]. 66 . This limit includes any records included in the aggregation. AggregateResult is a read-only sObject and is only used for query results. Note that any query that includes an aggregate function returns its results in an array of AggregateResult objects. you could use the AVG() aggregate function to find the average Amount for all your opportunities. For more information on aggregate functions. you should add a condition to the WHERE clause to reduce the amount of records processed by the query. such as SUM() and MAX(). For more information. Any changes to other fields that are used within the formula are not reflected in the formula field value until the record has been saved and re-queried in Apex. AggregateResult[] groupedResults = [SELECT AVG(Amount)aver FROM Opportunity]. AggregateResult[] groupedResults = [SELECT CampaignId. allow you to roll up and summarize your data in a query. Like other read-only sObject fields. you could find the average Amount for all your opportunities by campaign. see ”Aggregate Functions” in the Salesforce SOQL and SOSL Reference Guide. } Any aggregated field in a SELECT list that does not have an alias automatically gets an implied alias with a format expri. You can use aggregate functions without using a GROUP BY clause. System. If you encounter this limit.Language Constructs Working with SOQL Aggregate Functions The only situation in which it is not necessary to dereference an sObject field in the result of an SOQL query. The value of i starts at 0 and increments for every aggregated field with no explicit alias. Object avgAmount = groupedResults[0]. for (AggregateResult ar : groupedResults) { System. Aggregate functions become a more powerful tool to generate reports when you use them with a GROUP BY clause. see ”Using Aliases with GROUP BY” in the Salesforce SOQL and SOSL Reference Guide. Fields in records returned by SOSL queries must always be dereferenced. particularly for queries inside of triggers.LastName == 'Gordon') { c. } } Instead of using a SOQL query in a for loop. For more information. since it can process multiple batches of records through the use of internal calls to query and queryMore.LastName = 'Wayne'. To avoid long execution times.FirstName == 'Barbara' && c. Name FROM Account WHERE Name LIKE 'Acme%']) { // Your code without DML statements here } // Use this format for efficiency if you are executing DML statements // within the for loop for (List<Account> accts : [SELECT Id. Instead. ensure that the query is selective. } The following example demonstrates a SOQL query for loop used to mass update records. which minimizes the risk of hitting governor limits. non-selective SOQL queries may be terminated by the system. For example. SOQL queries must be selective. see SOQL For Loops on page 62. Developers will receive an error message when a non-selective query in a trigger executes against an object that contains more than 100. } } update contacts. if the results are too large.Language Constructs Working with Very Large SOQL Queries Working with Very Large SOQL Queries Your SOQL query may return so many sObjects that the limit on heap size is exceeded and an error occurs. Name FROM Account WHERE Name LIKE 'Acme%']) { // Your code here update accts. To avoid this error. 67 . the preferred method of mass updating records is to use batch Apex. LastName FROM Contact]) { for(Contact c : contacts) { if (c. use a SOQL query for loop instead. More Efficient SOQL Queries For best performance.000 records. use a SOQL query for loop as in one of the following examples: // Use this format if you are not executing DML statements // within the for loop for (Account a : [SELECT Id. Suppose you want to change the last name of a contact across all records for contacts whose first and last names match a specified criteria: public void massUpdate() { for (List<Contact> contacts: [SELECT FirstName. To resolve. the syntax below causes a runtime exception: Account[] accts = [SELECT Id FROM Account]. the index on Id is used.000 records (including soft-deleted records. Name and Owner fields). The performance of the SOQL query improves when two or more filters used in the WHERE clause meet the mentioned conditions. Salesforce. we will assume there are more than 100. there are other complex scenarios in which custom indexes won't be used. If SELECT COUNT() FROM Account WHERE Id IN (<list of account IDs>) returns fewer records than the selectivity threshold. Also. This will typically be the case since the list of IDs only contains a small amount of records. Typically.) Note that new data types. long text fields. and NOT STARTS WITH ◊ The CONTAINS operator is used in the filter and the number of rows to be scanned exceeds 333.com representative if your scenario isn't covered by these cases or if you need further assistance with non-selective queries. some formula fields. ◊ When comparing with an empty value (Name != '') • • • • However. for example with a query filter that is an indexed standard field. that is. let's analyze some queries.Language Constructs Working with Very Large SOQL Queries Selective SOQL Query Criteria • A query is selective when one of the query filters is on an indexed field and the query filter reduces the resulting number of rows below a system-defined threshold. and custom fields marked as External ID or Unique. In some circumstances. Examples of Selective SOQL Queries To better understand whether a query on a large object is selective or not. deleted records that are still in the Recycle Bin) for the Account sObject. and binary fields (fields of type blob. or encrypted text.000 records. making the query non-selective. may be added to Salesforce and fields of these types may not allow custom indexing. Note that this threshold is subject to change. 68 . This is because the CONTAINS operator requires a full scan of the index. Query 2: SELECT Id FROM Account WHERE Name != '' Since Account is a large object even though Name is indexed (primary key). For these queries. currency fields in a multicurrency organization. foreign keys (lookup or master-detail relationship fields). file. The selectivity threshold is 10% of the records for the first million records and less than 5% of the records after the first million records. • Custom Index Considerations for Selective SOQL Queries • The following fields are indexed by default: primary keys (Id.000.com Support can add custom indexes on request for customers. this filter returns most of the records. Query 1: SELECT Id FROM Account WHERE Id IN (<list of account IDs>) The WHERE clause is on an indexed field (Id). the selectivity threshold is subject to change. Contact your salesforce. NOT CONTAINS. typically complex ones. audit dates (such as LastModifiedDate). up to a maximum of 333. Fields that aren’t indexed by default might later be automatically indexed if the Salesforce optimizer recognizes that an index will improve performance for frequently run queries. the threshold may be higher. a custom index won't be used in these cases: ◊ The value(s) queried for exceeds the system-defined threshold mentioned above ◊ The filter operator is a negative operator such as NOT EQUAL TO (or !=). A custom index can't be created on these types of fields: multi-select picklists. Improving Performance by Not Searching on Null Values In your SOQL and SOSL queries. Public class TagWS { /* getThreadTags * * a quick method to pull tags not in the existing list * */ public static webservice List<String> getThreadTags(String threadId. Apex automatically assigns the single sObject record in the query result list to the L-value. For example: List<Account> accts = [SELECT Id FROM Account]. Filter out null values first to improve performance. List<String> retVals = new List<String>(). 69 .add('-' + x). In the following example.addAll(tags). when considered individually. Notice that the second line dereferences the field from the // query without assigning it to an intermediary sObject variable.Language Constructs Using SOQL Queries That Return One Record Query 3: SELECT Id FROM Account WHERE Name != '' AND CustomField__c = 'ValueA' Here we have to see if each filter. any records where the treadID value is null are filtered out of the returned values. // Note WHERE clause verifies that threadId is not null for(CSO_CaseThread_Tag__c t : [SELECT Name FROM CSO_CaseThread_Tag__c WHERE Thread__c = :threadId AND WHERE threadID != null]) { tagSet. } for(String x : origTagSet) { // return a minus version of it so the UI knows to clear it if(!tagSet. So let's focus on the second one. If the count of records returned by SELECT COUNT() FROM Account WHERE CustomField__c = 'ValueA' is lower than the selectivity threshold. List<String> tags) { system. and CustomField__c is indexed. // These lines of code are only valid if one row is returned from // the query.Name. Account acct = [SELECT Id FROM Account].contains(x)) retVals. When the L-value of an expression is a single sObject type.debug(LoggingLevel. Using SOQL Queries That Return One Record SOQL queries can be used to assign a single sObject value when the result list contains only one element. is selective.tags).Debug. Set<String> tagSet = new Set<String>().Name). the query is selective. origTagSet. Set<String> origTagSet = new Set<String>(). avoid searching records that contain null values. String name = [SELECT Name FROM Account]. As we saw in the previous example the first filter isn't selective.add(t. A runtime exception results if zero sObjects or more than one sObject is found in the list. This example queries Events that are related to an Account or Opportunity via the What field. The following describes how to use SOQL queries with polymorphic relationships in Apex. } //The following example also works because we limit to only 1 contact for (Account a : [SELECT Id. Another approach would be to use the TYPEOF clause in the SOQL SELECT statement. For example: for (Account a : [SELECT Id.Type IN ('Account'.Name FROM Contact WHERE FirstName = 'Caroline']. 'Opportunity')]. } Understanding Foreign Key and Parent-Child Relationship SOQL Queries The SELECT statement of a SOQL query can be any valid SOQL statement. Additionally.Contacts. or a Campaign.Account. One approach is to filter your results using the Type qualifier. the resulting sObjects can be referenced using normal field notation.Name). (SELECT LastName FROM Contacts) FROM Account WHERE Name = 'Acme']) { Contact[] cons = a. List<Event> = [SELECT Description FROM Event WHERE What. } return retVals.debug([SELECT Account. (SELECT LastName FROM Contacts LIMIT 1) FROM Account WHERE Name = 'testAgg']) { Contact c = a. For example: System. the What relationship field of an Event could be an Account. If you want more general information on polymorphic relationships. parent-child relationships in sObjects act as SOQL queries as well. see Understanding Polymorphic Keys and Relationships in the Force. } Working with Polymorphic Relationships in SOQL Queries A polymorphic relationship is a relationship between objects where a referenced object can be one of several different types. Name. For example.Language Constructs Understanding Foreign Key and Parent-Child Relationship SOQL Queries } for(String x : tagSet) { // return a plus version so the UI knows it's new if(!origTagSet. You can use SOQL queries that reference polymorphic fields in Apex to get results that depend on the object type referenced by the polymorphic field.Contacts.com SOQL and SOSL Reference. or an Opportunity. 70 .add('+' + x). This example also queries Events that are related to an Account or Opportunity via the What field. If foreign key joins are included. Name. List<Event> = [SELECT TYPEOF What WHEN Account THEN Phone WHEN Opportunity THEN Amount END FROM Event].contains(x)) retvals. including foreign key and parent-child record joins. and then assigns the owner objects to User or Group type variables before passing them to utility methods.Owner instanceof User) { User userOwner = merch.What references an Opportunity. The Apex parser first evaluates the local variable in code context before executing the SOQL or SOSL statement. so process accordingly } Note that you must assign the referenced sObject that the query returns to a variable of the appropriate type before you can pass it to another method. uses instanceof to determine the owner type. } public static void processOwnersOfMerchandise() { // Select records based on the Owner polymorphic relationship field List<Merchandise__c> merchandiseList = [SELECT TYPEOF Owner WHEN User THEN LastName WHEN Group THEN Email END FROM Merchandise__c].What references an Account. Event myEvent = eventFromQuery.Owner. } } } } Using Apex Variables in SOQL and SOSL Queries SOQL and SOSL statements in Apex can reference Apex code variables and expressions if they are preceded by a colon (:).Language Constructs Using Apex Variables in SOQL and SOSL Queries Note: TYPEOF is currently available as a Developer Preview as part of the SOQL Polymorphism feature. The following example uses instanceof to determine whether an Account or Opportunity is related to an Event. // We now have a list of Merchandise__c records owned by either a User or Group for (Merchandise__c merch: merchandiseList) { // We can use instanceof to check the polymorphic relationship type // Note that we have to assign the polymorphic reference to the appropriate // sObject type before passing to a method if (merch. if (myEvent.com. } else if (merch. For more information on enabling TYPEOF for your organization. These queries will return a list of sObjects where the relationship field references the desired object types. processUser(userOwner). The following example queries for User or Group owners of Merchandise__c custom objects using a SOQL query with a TYPEOF clause. Bind expressions can be used as: 71 .debug('Processed Group'). If you need to access the referenced object in a polymorphic relationship.Owner. processGroup(groupOwner).What instanceof Opportunity) { // myEvent.Owner instanceof Group) { Group groupOwner = merch. public class PolymorphismExampleClass { // Utility method for a User public static void processUser(User theUser) { System.What instanceof Account) { // myEvent. This use of a local code variable within a SOQL or SOSL statement is called a bind. you can use the instanceof keyword to determine the object type. contact salesforce. } // Utility method for a Group public static void processGroup(Group theGroup) { System. so process accordingly } else if (myEvent.debug('Processed User'). 'b'}. Contact C = new Contact(LastName='xxx'.Id). List<Account> offsetList = [SELECT Id FROM Account OFFSET :offsetVal]. // A bind with an expression that is itself a query result B = [SELECT Id FROM Account WHERE Name = :[SELECT Name FROM Account WHERE Id = :A. // A simple bind B = [SELECT Id FROM Account WHERE Id = :A. Note that this is of particular use with a list of IDs or Strings.Contacts. // One contact returned Contact D = B. // Binds in both the parent and aggregate queries B = [SELECT Id. // A bind with arithmetic B = [SELECT Id FROM Account WHERE Name = :('x' + 'xx')].substring(0. Account B. accountId=A. insert new Contact[]{C.Id) FROM Account WHERE Id = :A.Language Constructs Using Apex Variables in SOQL and SOSL Queries • • • • • • The search string in FIND clauses. allowing filtering on a dynamic set of values. The numeric value in OFFSET clauses.Id]. Task[] tt = [SELECT Id FROM Task WHERE WhoId IN :cc]. insert A.Id]. Note that a list of sObjects // can also be used--the Ids of the objects are used for // the bind Contact[] cc = [SELECT Id FROM Contact LIMIT 2].3)]. For example: Account A = new Account(Name='xxx').Name]. B = [SELECT Id FROM Account LIMIT :i].id)}. // A limit bind Integer i = 1. new Contact(LastName='yyy'. // An OFFSET bind Integer offsetVal = 10. The filter literals in WHERE clauses. Bind expressions can't be used with other clauses. The numeric value in LIMIT clauses. such as INCLUDES. The division names in WITH DIVISION clauses. (SELECT Id FROM Contacts WHERE Id = :C. String s = 'XXX'. // An IN-bind with an Id list. AccountId=A. The value of the IN or NOT IN operator in WHERE clauses.Id]. though it works with lists of any type. // A bind with expressions B = [SELECT Id FROM Account WHERE Name = :'XXXX'. // An IN-bind with a String list String[] ss = new String[]{'a'. 72 . List<List<SObject>> searchList = [FIND :myString1 IN ALL FIELDS RETURNING Account (Id. Warning: Use care when setting locks in your Apex code. // A SOSL query with binds in all possible clauses String myString1 String myString2 Integer myInt3 = String myString4 Integer myInt5 = = 'aaa'. You can use ALL ROWS to query records in your organization's Recycle Bin. While an sObject record is locked.Language Constructs Querying All Records with a SOQL Statement Account[] aa = [SELECT Id FROM Account WHERE AccountNumber IN :ss]. You cannot use the ALL ROWS keywords with the FOR UPDATE keywords. also locks the accounts that are returned: Account [] accts = [SELECT Id FROM Account LIMIT 2 FOR UPDATE]. Name WHERE Name LIKE :myString2 LIMIT :myInt3). no other program or user is allowed to make updates. Lead WITH DIVISION =:myString4 LIMIT :myInt5]. in addition to querying for two accounts. To lock a set of sObject records in Apex. Querying All Records with a SOQL Statement SOQL statements can use the ALL ROWS keywords to query all records in an organization. Locking Statements Apex allows developers to lock sObject records while they are being updated in order to prevent race conditions and other thread safety problems. = 'bbb'. 22. See Avoiding Deadlocks. 11. [SELECT COUNT() FROM Contact WHERE AccountId = a. Opportunity.Id ALL ROWS]).assertEquals(2. embed the keywords FOR UPDATE after any inline SOQL statement. Note: You cannot use the ORDER BY keywords in any SOQL query that uses locking. the following statement. For example: System. Contact. data manipulation language (DML) statements can modify their field values in the database in the transaction. including deleted records and archived activities. 73 . While the accounts are locked by this call. For example. = 'ccc'. below. Each savepoint you set counts against the governor limit for DML statements. Visualforce page or anonymous block that executes the Apex code. Avoiding Deadlocks Note that Apex has the possibility of deadlocks. then roll back to a savepoint that is not the last savepoint you generated. As a developer. Static variables are not reverted during a rollback. any changes made to the database are rolled back. For example. the static variables retain the values from the first run. all database changes are rolled back. any database changes are automatically committed. If you declare a savepoint as a static variable then try to use it across trigger contexts you will receive a runtime error. your business rules require that partial work (already executed DML statements) be “rolled back” so that the processing can continue in another direction. Apex gives you the ability to generate a savepoint. sometimes during the processing of records. Verify that you are using standard deadlock avoidance techniques by accessing tables and rows in the same order from all locations in an application. class method. use care when locking rows to ensure that you are not introducing deadlocks. then children. Note that there is no commit statement. as does any other procedural logic language involving updates to multiple database tables or rows. savepoint SP2 after that. However. the variable SP2 would no longer be valid. which in turn called an additional Apex class. If you try to run the trigger again. and then you rolled back to SP1. because each trigger invocation is a new execution context. a point in the request that specifies the state of the database at that time. To avoid such deadlocks. if you generated savepoint SP1 first. and the database can be restored to the same condition it was in at the time you generated the savepoint. If your Apex trigger completes successfully. the example above corresponds internally to calls to the query() and queryMore() methods in the SOAP API. References to savepoints cannot cross trigger invocations. suppose a Visualforce page called an Apex controller. Only when all the Apex code has finished running and the Visualforce page has finished running. The following limitations apply to generating savepoint variables and rolling back the database: • If you set more than one savepoint.Language Constructs Locking in a SOQL For Loop Locking in a SOQL For Loop The FOR UPDATE keywords can also be used within SOQL for loops. If the request does not complete successfully. If the entire request completes successfully. For example. are the changes committed to the database. For example: for (Account[] accts : [SELECT Id FROM Account FOR UPDATE]) { // Your code } As discussed in SOQL For Loops. Each rollback counts against the governor limit for DML statements. You will receive a runtime error if you try to use it. Any DML statement that occurs after the savepoint can be discarded. • • • • 74 . the Apex runtime engine first locks sObject parent records. that is. Web Service. If your Apex trigger does not complete successfully. all changes are committed to the database. the later savepoint variables become invalid. Transaction Control All requests are delimited by the trigger. You will receive a runtime error if you try to rollback the database additional times. The finally statement optionally identifies a block of code that is guaranteed to execute and allows you to clean up after the code enclosed in the try block. however. System. and finally statements can be used to gracefully recover from a thrown exception: • • • The try statement identifies a block of code in which an exception can occur.AccountNumber = '123'. System. Attempting to insert the sObject using the variable created before the rollback fails because the sObject variable has an ID. Account a = new Account(Name = 'xxx'). see Exception Class on page 469.assertEquals(null. Throw Statements A throw statement allows you to signal that an error has occurred.assertEquals(null. AccountNumber). Exception Statements Apex uses exceptions to note errors and other events that disrupt the normal flow of code execution. throw statements can be used to generate exceptions. AccountNumber). Updating or upserting the sObject using the same variable also fails because the sObject is not in the database and. // Create a savepoint while AccountNumber is null Savepoint sp = Database. A single try statement can have multiple associated catch statements.assertEquals('123'.Id]. To throw an exception. use the throw statement and provide it with an exception object to provide information about the specific error. AccountNumber).setSavepoint().rollback(sp). insert a.Id]. Create new a sObject to insert after a rollback. The catch statement identifies a block of code that can handle a particular type of exception. System. [SELECT AccountNumber FROM Account WHERE Id = :a. catch. A single try statement can have only one associated finally statement. and finally can be used to gracefully recover from an exception. [SELECT AccountNumber FROM Account WHERE Id = :a. while try. each catch statement must have a unique exception type. catch. thus.Language Constructs Exception Statements • The ID on an sObject inserted after setting a savepoint is not cleared after a rollback. For more information. cannot be updated. 75 . // Change the account number a. Try-Catch-Finally Statements The try. You can also create your own exceptions using the Exception class. update a.Id]. The following is an example using the setSavepoint and rollback Database methods. // Rollback to the previous null value Database. [SELECT AccountNumber FROM Account WHERE Id = :a. For example: throw exceptionObject. // Note that the general exception type.Language Constructs Try-Catch-Finally Statements Syntax The syntax of these statements is as follows: try { code_block } catch (exceptionType) { code_block } // Optional catch statements for other exception types. } catch (Exception e) { code_block } // Optional finally statement } finally { code_block } Example For example: try { // Your code here } catch (ListException e) { // List Exception handling code here } catch (Exception e) { // Generic exception handling code here } Note: Limit exceptions caused by an execution governor cannot be caught. 'Exception'. 76 . // must be the last catch block when it is used. See Understanding Execution Governors and Limits on page 214. This chapter includes the following: • • • • Triggers Apex scheduler (for Apex classes only) Anonymous Blocks AJAX Toolkit 77 . you can use the Ajax toolkit to invoke Web service methods implemented in Apex.Chapter 3 Invoking Apex In this chapter .. • • • • Triggers Apex Scheduler Anonymous Blocks Apex in AJAX You can invoke your Apex code using one of several mechanisms. or run code snippets in an anonymous block. You can write an Apex trigger and have your trigger code invoked for the events your trigger specifies—before or after a certain operation for a specified sObject type.. Finally. You can also write an Apex class and schedule it to run at specified intervals. Implementation Considerations Before creating triggers. See Understanding Execution Governors and Limits on page 214. if you update account A. and you will receive a runtime error. in turn. fire more triggers. See Triggers and Recovered Records on page 87. but not for standard child objects. or delete a record in its after trigger. If you query field history in a trigger. then you are indirectly updating account A in its before trigger. and the after insert trigger of contact B queries for account A and updates it using the DML update statement or database method. such as a ContactRole. For email messages. consider the following: • • • • upsert triggers fire both before and after insert or before and after update triggers as appropriate. click Your Name > Setup > Customize > Cases > Case Comments > Triggers. you will not see any history for the current transaction. Triggers can be divided into two types: • • Before triggers can be used to update or validate record values before they are saved to the database. after records have been deleted. such as a Contact or an Account. C. This includes both direct and indirect operations. if a trigger fires after an update of contact A. • • For case comments. if you update or delete a record in its before trigger. merge triggers fire both before and after delete triggers for the losing records and before update triggers for the winning record only. and the before update trigger of account A inserts contact B. Triggers can also modify other records of the same type as the records that initially fired the trigger. you will receive a runtime error. the Apex runtime engine considers all such operations a single unit of work and sets limits on the number of operations that can be performed to prevent infinite recursion. and to affect changes in other records. For example. After triggers can be used to access field values that are set by the database (such as a record's Id or lastUpdated field). the trigger can also modify contacts B. Because triggers can cause other records to change. Triggers that execute after a record has been undeleted only work with specific objects. and D. See Triggers and Merge Statements on page 86. click Your Name > Setup > Customize > Cases > Email Messages > Triggers. For example. such as logging into an audit table or firing asynchronous events with a queue. and because these changes can. Field history is not recorded until the end of a trigger. Additionally. you can have a trigger run before an object's records are inserted into the database. or even after a record is restored from the Recycle Bin. 78 . You can define triggers for any top-level standard object.Invoking Apex Triggers Triggers Apex can be invoked through the use of triggers. A trigger is Apex code that executes before or after the following types of operations: • • • • • • insert update delete merge upsert undelete For example. when the method is defined with the @future keyword. delete. Note that static variable values are reset between batches.0 and later. 79 . the batch of 200 records to process is further split into batches of 100 records.Invoking Apex Bulk Triggers • For Apex saved using Salesforce. no further splits of API batches occur. Bulk triggers can handle both single record updates and bulk operations like: • • • • Data import Force.com API version 20. Bulk Triggers All triggers are bulk triggers by default. A trigger invoked by an insert. if an API call causes a trigger to fire. but governor limits are not. Note: An Event object that is defined as recurring is not processed in bulk for insert.com Bulk API calls Mass actions. Do not use static variables to track state information between batches. You should always plan on processing more than one record at a time. and can process multiple records at a time. delete. or update of a recurring event or recurring task results in a runtime error when the trigger is called in bulk from the Force. that is.com API version 21. For Apex saved using Salesforce. or update triggers.0 or earlier. use the following syntax: trigger triggerName on ObjectName (trigger_events) { code_block } where trigger_events can be a comma-separated list of one or more of the following events: • • • • • • • before insert before update before delete after insert after update after delete after undelete Note: • • You can only use the webService keyword in a trigger when it is in a method defined as asynchronous. such as record owner changes and deletes Recursive Apex methods and triggers that invoke bulk DML statements Trigger Syntax To define a trigger.com API. If your Apex trigger does not complete successfully. or the API. not a Visualforce page. or the API. a Web service. Returns true if this trigger was fired before any record was saved. before update) { // Your code here } The code block of a trigger cannot contain the static keyword. after an undelete operation from the Salesforce user interface. Returns true if this trigger was fired after all records were saved. Returns true if this trigger was fired due to a delete operation. and the records can only be modified in before triggers. Note that this map is only available in update and delete triggers. If your Apex trigger completes successfully. These variables are contained in the System. Note that this sObject list is only available in insert and update triggers. or the API. Returns true if this trigger was fired due to an update operation.Invoking Apex Trigger Context Variables For example. any database changes are automatically committed. the following code defines a trigger for the before insert and before update events on the Account object: trigger myAccountTrigger on Account (before insert.) Returns a list of the new versions of the sObject records. isInsert isUpdate isDelete isBefore isAfter isUndelete new newMap A map of IDs to the new versions of the sObject records. Apex. 80 . from the Salesforce user interface. any changes made to the database are rolled back. In addition. Note that this map is only available in before update. Apex. Note that this sObject list is only available in update and delete triggers. after insert. oldMap A map of IDs to the old versions of the sObject records. Apex. from the Salesforce user interface. you do not have to manually commit any database changes made by a trigger. and after update triggers. from the Salesforce user interface. or an executeanonymous() API call. old Returns a list of the old versions of the sObject records. Trigger Context Variables All triggers define implicit variables that allow developers to access runtime context. Returns true if this trigger was fired after a record is recovered from the Recycle Bin (that is.Trigger class: Variable isExecuting Usage Returns true if the current context for the Apex code is a trigger. or the API. Returns true if this trigger was fired due to an insert operation. Apex. Triggers can only contain keywords applicable to an inner class. accountNumber). for (Account a : Trigger.industry). System.new) { if (a. For example.numberofemployees).annualrevenue). before update. a. } This trigger uses Boolean context variables like Trigger.assertEquals('industry'.new is a list of sObjects and can be iterated over in a for loop.isInsert) { for (Account a : Trigger. Note that although Trigger. for (Account a : Trigger.assertEquals(100.old list.new) { System. or used as a bind variable in the IN clause of a SOQL query: Trigger t on Account (after insert) { for (Account a : Trigger. both old and new. } } if (Trigger.name != 'okToDelete') { a. newMap. System. old.isInsert) { List<Contact> contacts = new List<Contact>(). 81 . Contact[] cons = [SELECT LastName FROM Contact WHERE AccountId IN :Trigger.isBefore) { if (Trigger. a.old) { if (a. that value is set to null in the new.new is a collection of // records. Note: If any record that fires a trigger includes an invalid field value (for example. Apex automatically // transforms the list of records into a list of corresponding Ids.assertEquals(100. System. the trigger accesses the records that will be // deleted with the Trigger. after insert.new list.new]. after update) { if (Trigger.assertEquals('xxx'.0. } } } else { // In before insert or before update triggers.isDelete to define code that only executes for specific trigger conditions: trigger myAccountTrigger on Account(before delete.name == 'bad') { a. before insert.accountNumber = 'yyy'. in this simple trigger. when used as a bind variable in a SOQL query.name. } // If the trigger is not a before trigger.addError('Bad name'). a. a. } else { if (Trigger. the trigger accesses the new records // with the Trigger. it must be an after trigger. after delete.isDelete) { // In a before delete trigger.new) { // Iterate over each sObject } // This single query finds every contact that is associated with any of the // triggering accounts. a. and oldMap trigger context variables. a formula that divides by zero).addError('You can\'t delete this record!').Invoking Apex Trigger Context Variables Variable size Usage The total number of records in a trigger invocation. Trigger.isBefore and Trigger. Id)). so nothing can update it. the updates become visible. Even though bad is thrown. trigger. after insert Not allowed.new is not available in before delete triggers. The object is deleted immediately after being inserted. You cannot delete trigger. The following table lists considerations about certain actions in different trigger events: Trigger Event Can change fields using trigger. so if the object is already in progress. } } }}} Context Variable Considerations Be aware of the following considerations for trigger context variables: • • • • trigger.add(new Contact (LastName = a.new) { if(a. Not allowed. is thrown. The deletion is deleted. trigger. Allowed. The updates are saved before the object is deleted.old is always read-only. but unnecessary. A runtime error Allowed. as trigger. recursion doing this incorrectly.Name.new code could cause an infinite is already saved. The updates are Not allowed. Can delete original object using a delete DML operation Not applicable. A runtime error saved before the object is is thrown. before insert Allowed. after update Not allowed. trigger. the updates become visible. A runtime error Allowed.new and trigger.Name == 'makeContact') { contacts. is thrown. A runtime error Not allowed.old cannot be used in Apex DML operations. Allowed. undeleted. The original object has not been created. as trigger.new is not saved. so a runtime exception is thrown. In all after triggers. nothing can reference it. AccountId = a. nothing can reference it.new. The original object has not been created.new. You can use an object to change its own field values using trigger. before update Not allowed.new Can update original object using an update DML operation Not applicable.new is already saved.Invoking Apex Context Variable Considerations for (Account a : Trigger. but only in before triggers. the error would be found by the governor limits. 82 . so if the object is undeleted. Allowed. before delete Allowed. A runtime error is thrown. } } insert contacts. A runtime error is thrown. so nothing can update it. new Can update original object using an update DML operation Can delete original object using a delete DML operation after delete Not allowed. Map<Id. Set<Id> pbeIds = new Set<Id>(). It then queries the PricebookEntries for their associated product color.color__c from pricebookentry where id in :pbeIds]). The following sections provide examples of idioms that should be used frequently when writing in bulk. Sets can be used to isolate distinct records.color__c = entries. is thrown.color__c. add its associated pricebook entry // to a set so there are no duplicates.new) oli. Allowed. // Now use the map to set the appropriate color on every OpportunityLineItem processed // by the trigger. the trigger iterates through the OpportunityLineItems in Trigger. } 83 . // Query the PricebookEntries for their associated product color and place the results // in a map.pricebookentryid).new to a set. Not allowed. For example.new) pbeIds. ensuring that the set contains only distinct elements. not available in after delete triggers.new and uses the map to assign the appropriate color. PricebookEntry> entries = new Map<Id. // When a new line item is added to an opportunity. PricebookEntry>( [select product2. The object has Not applicable.new is already been deleted.Invoking Apex Common Bulk Trigger Idioms Trigger Event Can change fields using trigger. but unnecessary. The object is deleted immediately after being inserted. Once the map is created. Using Maps and Sets in Bulk Triggers Set and map data structures are critical for successful coding of bulk triggers. and places the results in a map.add(oli. A runtime error Allowed. trigger oppLineTrigger on OpportunityLineItem (before insert) { // For every OpportunityLineItem record. A runtime error Not applicable. after undelete Common Bulk Trigger Idioms Although bulk triggers allow developers to process more records without exceeding execution governor limits. The object has is thrown.get(oli.old is not available in after undelete triggers. for (OpportunityLineItem oli : Trigger. trigger.product2.pricebookEntryId). trigger. this bulk trigger from the sample quoting application first adds each pricebook entry associated with the OpportunityLineItem records in Trigger. for (OpportunityLineItem oli : Trigger. they can be more difficult for developers to understand and code because they involve processing batches of several records at a time. this trigger copies the value of the // associated product's color to the new record. while maps can be used to hold query results organized by record ID. already been deleted. it is possible that the error message may not be correct by the time the request is finished. if two records are inserted with the same value for a unique field. For example. 3.oldMap. That means the error message reported by the second record is no longer valid. 84 . This associates the trigger with the most recent version of Apex and the API. That retry cycle assigns new keys to the new records. For a custom object. the related opportunity is retrieved from Trigger.oldMap. click Your Name > Setup > Customize > Cases > Email Messages > Triggers. click New. For every quote returned by the query. For case comments. Use the default values for all versions. Defining Triggers Trigger code is stored as metadata under the object with which they are associated. For the Attachment.get(q. this trigger from the sample quoting app uses Trigger. click Your Name > Setup > Customize. Leave this checkbox deselected if you only want to store the code in your organization's metadata.opportunity__c). the error message for the duplicate record includes the ID of the first record. and Note standard objects. the retry logic in bulk operations causes a rollback/retry cycle to occur. ContentDocument. once the system rolls back the changes and re-inserts the first record by itself.addError('Cannot delete opportunity with a quote'). In the Triggers related list. you can also specify which version of each managed package to use with this trigger. such as the Developer Console or the Force. you can also use the Metadata API. If your organization has installed managed packages from the AppExchange. The set is then used as part of a query to create a list of quotes associated with the opportunities being processed by the trigger. as well as each managed package. click Your Name > Setup > Create > Objects and click the name of the object.oldMap ID-to-sObject maps to correlate records with query results. For these objects. For email messages. click Your Name > Setup > Customize > Cases > Case Comments > Triggers. create a trigger using development tools. reporting the ID of the first record. For campaign members. However. This checkbox is selected by default. click Your Name > Setup > Customize > Campaigns > Campaign Member > Triggers. the record receives a new ID.keySet()). click the name of the object.oldMap. and you also have an insert event defined for a trigger. } } Using Triggers to Insert or Update Records with Unique Fields When an insert or upsert event causes a record to duplicate the value of a unique field in another new record in that batch.oldMap to create a set of unique IDs (Trigger.newMap and Trigger. To define a trigger in Salesforce: 1. 4. then click Triggers. the second duplicate record fails. you can’t create a trigger in the Salesforce user interface. Alternatively. Click Version Settings to specify the version of Apex and the API used with this trigger.com IDE. When there are triggers present.Invoking Apex Defining Triggers Correlating Records with Query Results in Bulk Triggers Use the Trigger. Click Apex Trigger and select the Is Active checkbox if the trigger should be compiled and enabled.keySet()]) { Trigger. You can specify an older version of a managed package if you want to access components or functionality that differs from the most recent package version. However. For example.oldMap and prevented from being deleted: trigger oppTrigger on Opportunity (before delete) { for (Quote__c q : [SELECT opportunity__c FROM quote__c WHERE opportunity__c IN :Trigger. 2. For a standard object. an editor is available with the following functionality: Syntax highlighting The editor automatically applies syntax highlighting for keywords and all functions and operators.com API. The Apex Trigger Editor When editing Visualforce or Apex. If any changes are made to object names or fields that are used in the trigger. 85 . Click Save. delete. when the method is defined with the @future keyword. To define a trigger. enter the Apex for the trigger. class. the isValid flag is set to false until the Apex compiler reprocesses the code. or when a user re-saves the trigger in metadata. that is. you can choose to prevent records from being deleted if they’re in a lookup relationship.Invoking Apex Defining Triggers 5. class. If a lookup field references a record that has been deleted. including superficial changes such as edits to an object or field description. either in the Visualforce development mode footer or from Setup. or trigger. Alternatively. enter the new string in the Replace textbox and click replace to replace just that instance. or trigger. use the following syntax: trigger triggerName on ObjectName (trigger_events) { code_block } where trigger_events can be a comma-separated list of one or more of the following events: • • • • • • • before insert before update before delete after insert after update after delete after undelete Note: • • You can only use the webService keyword in a trigger when it is in a method defined as asynchronous. enter a string in the Search textbox and click Find Next. Recompiling occurs when the trigger is next executed. A single trigger can be up to 1 million characters in length. or Replace All to replace that instance and all other instances of the search string that occur in the page. 6. A trigger invoked by an insert. • To replace a found search string with another string. Salesforce clears the value of the lookup field by default. In the Body text box. or update of a recurring event or recurring task results in a runtime error when the trigger is called in bulk from the Force. • To make the search operation case sensitive. select the Match Case option. Search ( ) Search enables you to search for text within the current page. Note: Triggers are stored with an isValid flag that is set to true as long as dependent metadata has not changed since the trigger was last compiled. To use search. Go to line ( ) This button allows you to highlight a specified line number. If the line is not currently visible. No triggers for records related to the contacts. to replace an <h1> tag with an <h2> tag and keep all the attributes on the original <h1> intact. The after delete trigger fires. 3.Invoking Apex Triggers and Merge Statements • To use a regular expression as your search string. search for <h1(\s+)(. and sets the MasterRecordId field on the deleted records. 86 . they fire delete and update events as follows: Deletion of losing records A single merge operation fires a single delete event for all records that are deleted in the merge. only the delete and update contact triggers fire. Triggers and Merge Statements Merge events do not fire their own trigger events. Instead. 2. The regular expressions follow JavaScript's regular expression rules. if two contacts are merged.*)> and replace it with <h2$1$2>. When a record is deleted after losing a merge operation. such as accounts or opportunities. and so on) from the found search string. The before delete trigger fires. If your application requires special handling for deleted records that occur as a result of a merge. The MasterRecordId field is only set in after delete trigger events. select the Regular Expressions option.old. the replace operation can also bind regular expression group variables ($1. For example. This can be used with go to line ( ) to quickly navigate through the editor. the editor scrolls to that line. For example. its MasterRecordId field is set to the ID of the winning record. To determine which records were deleted as a result of a merge operation use the MasterRecordId field in Trigger. The system deletes the necessary records due to the merge. Font size Select a font size from the drop-down list to control the size of the characters displayed in the editor. fire. The following is the order of events when a merge occurs: 1. A search using regular expressions can find strings that wrap over more than one line. Undo ( ) and Redo ( ) Use undo to reverse an editing action and redo to recreate an editing action that was undone. Line and column position The line and column position of the cursor is displayed in the status bar at the bottom of the editor. Update of the winning record A single merge operation fires a single update event for the winning record only. Line and character count The total number of lines and characters is displayed in the status bar at the bottom of the editor. If you use the replace operation with a string found by a regular expression. you need to use the after delete trigger event. $2. assigns new parent records to the child records. Any child records that are reparented as a result of the merge operation do not fire triggers. The after undelete trigger event only fires for the following objects: • • • • • • • • • • • • • • Account Asset Campaign Case Contact ContentDocument Contract Custom objects Event Lead Opportunity Product Solution Task Triggers and Order of Execution When you save a record with an insert. the Opportunity is also recovered. For example. These are also called undeleted records. only the Account after undelete trigger event executes. On the server. Normal update triggers apply. Salesforce performs the following events in order. Salesforce: 1. the browser runs JavaScript validation if the record contains any dependent picklist fields. Note: Before Salesforce executes these events on the server. The validation limits each dependent picklist field to its available values. Salesforce runs system validation to check the record for: • • • • Compliance with layout-specific rules Required values at the layout level and field-definition level Valid field formats Maximum field length 87 . No other validation occurs on the client side. 2. Triggers and Recovered Records The after undelete trigger event only works with recovered records—that is. if you delete an Account. If the request came from a standard UI edit page.Invoking Apex Triggers and Recovered Records 4. update. or upsert statement. Loads the new record field values from the request and overwrites the old values. records that were deleted and then recovered from the Recycle Bin through the undelete DML statement. If there is an after undelete trigger event associated with both the Account and the Opportunity. an Opportunity may also be deleted. The after undelete trigger events only run on top-level objects. The system does the specific updates required for the master record. When you recover the Account from the Recycle Bin. Loads the original record from the database or initializes the record for an upsert statement. Additional Considerations Please note the following when working with triggers: • When Enable Validation and Triggers from Lead Convert is selected. If the trigger Stage and incoming Stage are the same. see “Customizing Lead Settings” in the Salesforce online help. 11. If the record was updated with workflow field updates. Executes assignment rules. 17. Executes Criteria Based Sharing evaluation. Executes post-commit logic. and runs any user-defined validation rules. 9. 14. performs calculations and updates the roll-up summary field in the parent record. Note: During a recursive save. 4. ◊ If you reset Stage to a value specified in an API call or incoming from the user interface. Saves the record to the database. If there are workflow field updates. Executes workflow rules. performs calculations and updates the roll-up summary field in the parent record. the triggers run immediately after the opportunity is created. the triggers are not fired again. 13. such as sending email. 5. Executes auto-response rules. Executes escalation rules. the Forecast Category value on the opportunity record defaults to the one associated with trigger Stage. The only system validation that Salesforce doesn't run a second time (when the request comes from a standard UI edit page) is the enforcement of layout-specific rules. Parent record goes through save procedure. the opportunity record contains those exact values. the Forecast Category is not defaulted. If no value for Forecast Category is specified and the incoming Stage is different than the trigger Stage. Salesforce skips steps 7 through 14. such as verifying that all required fields have a non-null value. the behavior is as follows: ◊ If you set Stage and Forecast Category. updates the record again. If the fields have already been set to a value.Invoking Apex Triggers and Order of Execution Salesforce doesn't perform system validation in this step when the request comes from other sources. 12. Commits all DML operations to the database. 10. but doesn't commit yet. 7. 6. Grand-parent record goes through save procedure. Executes all before triggers. Executes all after triggers. 8. before the opportunity contact role is created. ◊ If you set Stage but not Forecast Category. If the parent record is updated. the Forecast Category value should also come from the API call or user interface. the Forecast Category defaults to the one associated with trigger Stage. 3. Runs most system validation steps again. If the record contains a roll-up summary field or is part of a cross-object workflow. in addition to standard validations. Note: The before and after triggers fire one more time only if something needs to be updated. Custom validation rules are not run again. • 88 . 15. if the lead conversion creates an opportunity and the opportunity has Apex before triggers associated with it. fires before and after triggers one more time (and only one more time). and a grand-parent record contains a roll-up summary field or is part of a cross-object workflow. If you are using before triggers to set Stage and Forecast Category for an opportunity record. For more information. such as an Apex application or a SOAP API call. 16. ) Note: Inserts.old is the original value of 1. the following events occur in order: 1. Some examples include: • • • • • • • • • • • • Cascading delete operations. rather than 10. and a workflow rule field update fires and increments it to 11. If any opportunity products contain unique custom fields. but the object before the initial update was made. Operations that Don't Invoke Triggers Triggers are only invoked for data manipulation language (DML) operations that are initiated or processed by the Java application server. not contact triggers. and deletes on person accounts fire account triggers. Cascading updates of child records that are reparented as a result of a merge operation Mass campaign status changes Mass division transfers Mass address updates Mass approval request transfers Mass email actions Modifying custom field data types Renaming or replacing picklists Managing price books Changing a user's default division with the transfer division option checked Changes to the following objects: ◊ BrandTemplate ◊ MassEmailTemplate ◊ Folder • Update account triggers don't fire before or after a business account record type is changed to person account (or a person account record type is changed to business account. For example. there is an exception. some system bulk operations don't currently invoke triggers. • Trigger. contacts.old in the last update trigger won’t contain the version of the object immediately prior to the workflow update. Before triggers associated with the following operations are only fired during lead conversion if validation and triggers for lead conversion are enabled in the organization: • insert of accounts. However. Trigger. The parent opportunity is saved according to the list of events shown above. Consequently.old contains a version of the objects before the specific update that fired the trigger.Invoking Apex Operations that Don't Invoke Triggers • If you are cloning an opportunity with products. you must null them out before cloning the opportunity. In the update trigger that fires after the workflow field update. suppose an existing record has a number field with an initial value of 1. and opportunities 89 . the field value of the object obtained from Trigger. updates. you must return to the opportunity and fix the errors before cloning. Records that did not initiate a delete don't cause trigger evaluation. 2. A user updates this field to 10. as would typically be the case. When a record is updated and subsequently triggers a workflow rule field update. The opportunity products are saved according to the list of events shown above. Note: If errors occur on an opportunity product. roll-up summary fields do get updated.Invoking Apex Entity and Field Considerations in Triggers • update of accounts and contacts Opportunity triggers are not fired when the account owner changes as a result of the associated opportunity's owner changing. Fields Not Updateable in Before Triggers Some field values are set during the system save operation. these fields cannot be modified or accurately detected in before insert or before update triggers. and workflow rules associated with the opportunity do run. Note the following for the ContentVersion object: • Content pack operations involving the ContentVersion object. even if the opportunity product changes the opportunity.isWon Opportunity. or when an opportunity product schedule changes an opportunity product.activatedDate Contract. As a result. However. For example. which occurs after before triggers have fired. Note: Content packs are revised when a slide inside of the pack is revised. don't invoke triggers.ForecastCategory Opportunity. When you modify an opportunity product on an opportunity.isClosed Solution. Some examples include: • • • • • • • • • • • • Task. The getContent and getContentAsPDF PageReference methods aren't allowed in triggers.activatedById Case. including slides and slide autorevision.isClosed Contract.amount* Opportunity. the before and after triggers and the validation rules don't fire for the opportunity. Entity and Field Considerations in Triggers QuestionDataCategorySelection Entity Not Available in After Insert Triggers The after insert trigger that fires after inserting one or more Question records doesn’t have access to the QuestionDataCategorySelection records that are associated with the inserted Questions.isClosed Opportunity. • • Values for the TagCsv and VersionData fields are only available in triggers if the request to create or update ContentVersion records originates from the API. You can't use before or after delete triggers with the ContentVersion object. the following query doesn’t return any results in an after insert trigger: QuestionDataCategorySelection[] dcList = [select Id.isReviewed Id (for all records)** createdDate (for all records)** lastUpdated (for all records) 90 .DataCategoryName from QuestionDataCategorySelection where ParentId IN :questions]. • • • • CollaborationGroup CollaborationGroupMember FeedItem FeedComment Additional Considerations for Chatter Objects Things to consider about FeedItem and FeedComment triggers: • • • Only FeedItems of Type TextPost. Note the following for the CollaborationGroup and CollaborationGroupMember objects: • When CollaborationGroupMember is updated. shouldn’t have before update and after update triggers. When used on Trigger. Amount can be modified by a before trigger. 19. ** Id and createdDate can be detected in before update triggers.0. User status updates don't cause the FeedItem triggers to fire. and ContentPost can be inserted. As a result. and therefore. shouldn’t have after undelete triggers. • • FeedItem FeedComment Entities Not Supported in After Undelete Triggers Certain objects can’t be restored. CollaborationGroup is automatically updated as well to ensure that the member count is correct. and 20.0. the user running the code must be a member of that group. the fields of a ContentVersion associated with the FeedComment (obtained through FeedComment. the custom error message is displayed in the application interface and logged.old records in delete triggers. the ContentData field is not available in any delete trigger. CollaborationGroup update triggers run as well. To post to a private group. While FeedPost objects were supported for API versions 18. Note: Users experience less of a delay in response time if errors are added to before triggers. Apex code uses additional security when executing in a Chatter context. • • For FeedComment before insert and after insert triggers. Entities Not Supported in Update Triggers Certain objects can’t be updated. you can set the CreatedById field to be a member of the group in the FeedItem record. and on Trigger. For FeedItem the following fields are not available in the before insert trigger: ◊ ContentSize ◊ ContentType In addition.new records in insert and update triggers.0.0. If the running user isn't a member. LinkPost. don't use any insert or delete triggers saved against versions prior to 21. when CollaborationGroupMember update or delete triggers run. 91 . Trigger Exceptions Triggers can be used to prevent DML operations from occurring by calling the addError() method on a record or field.Invoking Apex Trigger Exceptions * When Opportunity has no lineitems. and therefore invoke the before or after insert trigger.RelatedRecordId) are not available. and therefore. but cannot be modified. } } For more information on governor limits. See Bulk DML Exception Handling on page 278. see Understanding Execution Governors and Limits on page 214.new collection to a set. While this might support most user interface events. requires developers to write logic that supports bulk operations. the runtime engine still processes every record in the operation to compile a comprehensive list of errors. This pattern captures all incoming records within the request while limiting the number of SOQL queries. Best Practices for Designing Bulk Programs The following are the best practices for this design pattern: • Minimize the number of data manipulation language (DML) operations by adding records to collections and performing DML operations against these collections. If a trigger ever throws an unhandled exception. It assumes that less than 100 records are pulled in during a trigger invocation.id]. Apex triggers are optimized to operate in bulk. before update) { for(mileage__c m : Trigger.Invoking Apex Trigger and Bulk Request Best Practices A subset of the records being processed can be marked with the addError() method: • • If the trigger was spawned by a DML statement in Apex.keySet().com API. the specified error message is escaped in the Salesforce user interface. the escaped markup displays as text and isn’t rendered in the user interface. List<User> c = [SELECT Id FROM user WHERE mileageid__c in :ids].new.com API version 27. before update) { User c = [SELECT Id FROM User WHERE mileageid__c = Trigger. before update) { Set<ID> ids = Trigger. the runtime engine sets aside the bad records and attempts to do a partial save of the records that did not generate errors.new[0]. by definition.Id]. it does not support bulk operations invoked through the SOAP API or Visualforce. which. 92 . This example demonstrates the correct pattern to support the bulk nature of triggers while respecting the governor limits: Trigger MileageTrigger on Mileage__c (before insert. any one error results in the entire operation rolling back. If the error message contains HTML markup. If more than 20 records are pulled into this request.0 and later. Note: For Apex saved using Salesforce. However. } This is another example of a flawed programming pattern. This is an example of a flawed programming pattern.new){ User c = [SELECT Id FROM user WHERE mileageid__c = m. If the trigger was spawned by a bulk DML call in the Force. It assumes that only one record is pulled in during a trigger invocation. Trigger and Bulk Request Best Practices A common development pitfall is the assumption that trigger invocations never include more than one record. trigger MileageTrigger on Mileage__c (before insert. all records are marked with an error and no further processing takes place. the trigger would exceed the SOQL query limit of 100 SELECT statements: trigger MileageTrigger on Mileage__c (before insert. then using the set in a single SOQL query. } This pattern respects the bulk nature of the trigger by passing the Trigger. import wizards. The Schedulable interface contains one method that must be implemented. consider API bulk updates. see “Monitoring Scheduled Jobs” in the Salesforce online help. For more information about the Schedule Apex page. which can be placed in single SOQL statement used with the IN clause. mass record changes through the user interface. click Your Name > Setup > Monitoring > Scheduled Jobs. then specify the schedule using either the Schedule Apex page in the Salesforce user interface. see “Scheduling Apex” in the Salesforce online help. See Also: What are the Limitations of Apex? Apex Scheduler To invoke Apex classes to run at specific times.schedule method. see “Apex Class Security Overview” in the Salesforce online help. You can evaluate your current count by viewing the Scheduled Jobs page in Salesforce or programmatically using SOAP API to query the CronTrigger object. To monitor or stop the execution of a scheduled Apex job using the Salesforce user interface.Invoking Apex Apex Scheduler • Minimize the number of SOQL statements by preprocessing records and generating sets. Implementing the Schedulable Interface To schedule an Apex class to run at regular intervals. whether the user has permission to execute the class or not. Important: Salesforce only adds the process to the queue at the scheduled time. The following example implements the Schedulable interface for a class called mergeNumbers: global class scheduledMerge implements Schedulable{ global void execute(SchedulableContext SC) { 93 . first write an Apex class that implements the Salesforce-provided interface Schedulable. The scheduler runs as system: all classes are executed. For more information. global void execute(SchedulableContext sc){} The implemented method must be declared as global or public. You cannot update an Apex class if there are one or more active scheduled jobs for that class. You can only have 25 classes scheduled at one time. Use this method to instantiate the class you want to schedule. first implement the Schedulable interface for the class. In particular. You must be able to guarantee that the trigger will not add more scheduled classes than the 25 that are allowed. For more information on setting class permissions. or the System. Use extreme care if you are planning to schedule a class from a trigger. execute. Actual execution may be delayed based on service availability. we recommend that all processing take place in a separate class. Tip: Though it's possible to do additional processing in the execute method. and all cases where more than one record can be updated at a time. Name FROM Account WHERE Name = 'testScheduledApexFromTestMethod']. global class TestScheduledApexFromTestMethod implements Schedulable { // This test runs a scheduled job at midnight Sept. the scheduled job executes at the end of your test method for Apex saved using Salesforce. a. Use the Test methods startTest and stopTest around the System. System. The following example implements the Schedulable interface for a batch Apex class called batchable: global class scheduledBatchable implements Schedulable{ global void execute(SchedulableContext sc) { batchable b = new batchable(). use the System.schedule('Merge Job'. ct. NextFireTime FROM CronTrigger WHERE Id = :ctx. 3rd. scheduledMerge m = new scheduledMerge(). If you don’t include the System.assertEquals('2022-09-03 00:00:00'. String sch = '20 30 8 10 2 ?'. All asynchronous calls made after the startTest method are collected by the system. } } The following example uses the System.assertEquals(CRON_EXP. m). all asynchronous processes are run synchronously. but not in earlier versions.abortJob method with the ID returned by the. To stop execution of a job that was scheduled.name = 'testScheduledApexFromTestMethodUpdated'. ct. you must ensure that the scheduled job is finished before testing against the results. 2022 public static String CRON_EXP = '0 0 0 3 9 ? 2022'.schedule method to ensure it finishes before continuing your test.assertEquals(0. Use this method to track the progress of the scheduled job. When stopTest is executed. CronExpression. } } Use the SchedulableContext object to keep track of the scheduled job once it's scheduled. System.NextFireTime)).getTriggerId()].schedule method within the startTest and stopTest methods.Invoking Apex Apex Scheduler mergeNumbers M = new mergeNumbers(). TimesTriggered. update a. Testing the Apex Scheduler The following is an example of how to test using the Apex scheduler. Account a = [SELECT Id. This is the class to be tested. String. The System.schedule method starts an asynchronous process. database. You can also use the Schedulable interface with batch Apex classes.CronExpression).valueOf(ct. 94 . The SchedulableContext method getTriggerID returns the Id of the CronTrigger object associated with this scheduled job as a string.0 and later. sch.getTriggerID method. global void execute(SchedulableContext ctx) { CronTrigger ct = [SELECT Id. system. System.TimesTriggered).com API version 25.Schedule method to implement the above class. This means that when you test scheduled Apex.executebatch(b). import wizards. ct. In particular. // Get the information from the CronTrigger API object CronTrigger ct = [SELECT Id.assertEquals(0. name FROM account WHERE id = :a. NextFireTime FROM CronTrigger WHERE id = :jobId]. [SELECT id.assertEquals('2022-09-03 00:00:00'. ct. Name FROM Account WHERE Id = :a. and all cases where more than one record can be updated at a time.valueOf(ct.CRON_EXP.schedule('testBasicScheduledApex'. TestScheduledApexFromTestMethod. and the name of the class.TimesTriggered).Schedule Method After you implement a class with the Schedulable interface.Invoking Apex Apex Scheduler } } The following tests the above class: @istest class TestClass { static testmethod void test() { Test. CronExpression.startTest().Id]. [SELECT Id. TimesTriggered. mass record changes through the user interface.assertNotEquals('testScheduledApexFromTestMethodUpdated'.assertEquals('testScheduledApexFromTestMethodUpdated'. an expression used to represent the time and date the job is scheduled to run. use the System. Note: Use extreme care if you are planning to schedule a class from a trigger.Schedule method takes three arguments: a name for the job.id].CRON_EXP. // Verify the expressions are the same System. String. You must be able to guarantee that the trigger will not add more scheduled classes than the 25 that are allowed. The System. Account a = new Account(). consider API bulk updates. System.assertEquals(TestScheduledApexFromTestMethod.CronExpression). Test.Name). // Verify the next time the job will run System. System. a.name). whether the user has permission to execute the class or not. insert a. This expression has the following syntax: Seconds Minutes Hours Day_of_month Month Day_of_week optional_year 95 . // Verify the job has not run System. // Schedule the test job String jobId = System. The scheduler runs as system: all classes are executed. new TestScheduledApexFromTestMethod()).Name = 'testScheduledApexFromTestMethod'.stopTest(). } } Using the System.NextFireTime)).Schedule method to execute it. . . use JAN-MAR to specify more than one month. . MAR.* ? / L # optional_year . Description Delimits values. The System. .* / .* ? / L W . The following are the values for the expression: Name Seconds Minutes Hours Day_of_month Month Values 0–59 0–59 0–23 1–31 1–12 or the following: • JAN • FEB • MAR • APR • MAY • JUN • JUL • AUG • SEP • OCT • NOV • DEC 1–7 or the following: • SUN • MON • TUE • WED • THU • FRI • SAT null or 1970–2099 Special Characters None None . Actual execution may be delayed based on service availability. Specifies a range. For example.* / The special characters are defined as follows: Special Character . APR to specify more than one month.Schedule method uses the user's timezone for the basis of all schedules. use JAN.Invoking Apex Apex Scheduler Note: Salesforce only adds the process to the queue at the scheduled time.* / Day_of_week . - 96 . . For example. and the 20th is a Saturday. This is only available for Day_of_month and Day_of_week. ? / L W # Specifies the nth day of the month. For example.Invoking Apex Apex Scheduler Special Character * Description Specifies all values. the job is scheduled for every month. starting on the first of the month. and the first is a Saturday. Specifies the end of a range (last). If you specify 1W. in the format weekday#day_of_month. 97 . the Apex class runs every fifth day of the month. if you specify 2L. Specifies no specific value. When used with a Day_of_week value. This is only available for Day_of_month. which is the following Monday. and the number after the slash is the interval amount. For example. it always means 7 or SAT. Class runs the last Friday of every month at 10 PM. Class runs Monday through Friday at 10 AM. Expression 0 0 13 * * ? 0 0 22 ? * 6L 0 0 10 ? * MON-FRI 0 0 20 * * ? 2010 Description Class runs every day at 1 PM. you are specifying the last Monday of the month. The following are some examples of how to use the expression. the class runs on the 19th. For example. and so on. The number after the # specifies the day of the month. For example. if you specify 1/5 for Day_of_month. specifying 2#2 means the class runs on the second Monday of every month. February 28 for leap years. and is generally used when specifying a value for one and not the other. Class runs every day at 8 PM during the year 2010. such as January 31. This is only available for Day_of_week. For example. the class does not run in the previous month. Tip: Use the L and W together to specify the last weekday of the month. This is only available for Day_of_month and Day_of_week. L always means the last day of the month. The number before the # specifies weekday (SUN-SAT). if Month is specified as *. Do not use a range of values with L as the results might be unexpected. if you specify 20W. When used with Day_of_week by itself. Specifies the nearest weekday (Monday-Friday) of the given day. it means the last of that type of day in the month. but on the third. The number before the slash specifies when the intervals will begin. When used with Day of month. Specifies increments. If your Apex trigger does not complete successfully. Actual execution may be delayed based on service availability. You can't use the getContent and getContentAsPDF PageReference methods in scheduled Apex. the class proschedule implements the Schedulable interface. mass record changes through the user interface. User-defined methods cannot include the keyword static. The class is scheduled to run at 8 AM.com IDE. You can evaluate your current count by viewing the Scheduled Jobs page in Salesforce or programmatically using SOAP API to query the CronTrigger object. and then uses an anonymous block of Apex to insert a contact with that name and address into the database. Note the following about the content of an anonymous block (for executeAnonymous. Synchronous Web service callouts are not supported from scheduled Apex. any database changes are automatically committed. However.schedule('One Time Pro'. or to write code that changes dynamically at runtime. You must be able to guarantee that the trigger will not add more scheduled classes than the 25 that are allowed. we recommend that all processing take place in a separate class. callouts are supported from the batch class. • • • • Anonymous Blocks An anonymous block is Apex code that does not get stored in the metadata. If your Apex trigger completes successfully. sch. such as a name and address. For example. on the 13th of February. but that can be compiled and executed using one of the following: • • • Developer Console Force. p). consider API bulk updates. import wizards. the code String): • • • • Can include user-defined methods and exceptions. system. if your scheduled Apex executes a batch job. In particular. To be able to make callouts.com IDE The executeAnonymous SOAP API call: ExecuteAnonymousResult executeAnonymous(String code) You can use anonymous blocks to quickly evaluate Apex on the fly. Use extreme care if you are planning to schedule a class from a trigger. You can only have 25 classes scheduled at one time. make an asynchronous callout by placing the callout in a method annotated with @future(callout=true) and call this method from scheduled Apex. 98 . such as in the Developer Console or the Force. String sch = '0 0 8 13 2 ?'. Though it's possible to do additional processing in the execute method. Apex Scheduler Best Practices and Limits • • Salesforce only adds the process to the queue at the scheduled time.Invoking Apex Anonymous Blocks In the following example. See Using Batch Apex. and all cases where more than one record can be updated at a time. proschedule p = new proschedule(). any changes made to the database are rolled back. You do not have to manually commit any database changes. you might write a client Web application that takes input from a user. See also Working with Logs in the Developer Console and the Force. including the output of any calls to the System. including the class. } void myProcedure2() { int1++. the Integer int must be declared while myProcedure1 does not: Integer int1 = 0. void myProcedure1() { myProcedure2(). For example. For example.Invoking Apex Apex in AJAX • • Unlike classes and triggers. anonymous blocks execute as the current user and can fail to compile if the code violates the user's object.0/connection. include the following lines in your AJAX code: <script src="/soap/ajax/15. you can call the following Apex class: global class myClass { webService static Id makeContact(String lastName. This method returns a result similar to the API's result type.0/apex. 99 . it has no meaning. use one of the following two methods: • • Execute anonymously via sforce. including any errors that occur The debug log content.js" type="text/javascript"></script> Note: For AJAX buttons. Do not have a scope other than local. though it is legal to use the global access modifier. Account a) { Contact c = new Contact(LastName = lastName. Use a class WSDL. To do so.Id). method.debug method (see Understanding the Debug Log on page 199) The Apex stack trace of any uncaught code execution exceptions.apex.js" type="text/javascript"></script> <script src="/soap/ajax/15. AccountId = a.com IDE. The scope of the method is limited to the anonymous block. } myProcedure1(). and line number for each call stack element For more information on executeAnonymous().and field-level permissions. The return result for anonymous blocks includes: • • • Status information for the compile and execute phases of the call. To invoke Apex. Even though a user-defined method can refer to itself or later methods without the need for forward declarations. see SOAP API and SOAP Headers for Apex. but as a JavaScript structure. variables cannot be referenced before their actual declaration. use the alternate forms of these includes. Apex in AJAX The AJAX toolkit includes built-in support for invoking Apex through anonymous blocks or public webService methods.executeAnonymous (script). In the following example. you must include it in the JavaScript code when you invoke the class. {lastName:"Smith". use {} as the third parameter for sforce. "getContextUserName". To call a webService method with no parameters."makeContact". } } Use the following JavaScript code: var contextUser = sforce.debug.execute. it is listed under Developer Settings.Invoking Apex Apex in AJAX return c.apex. var id = sforce.apex.apex. log in to your Salesforce organization and navigate to Your Name > Setup > Create > Packages.execute("myNamespace. "getContextUserName". The execute method takes primitive data types. Both examples result in native JavaScript values that represent the return type of the methods. For example.id.execute("myClass". to call the above class. sObjects. For example. {}). } } By using the following JavaScript code: var account = sforce.getFirstName(). to call the following Apex class: global class myClass{ webService static String getContextUserName() { return UserInfo. 100 . Note: If a namespace has been defined for your organization.myClass". {}).apex. the JavaScript code from above would be rewritten as follows: var contextUser = sforce. To verify whether your organization has a namespace. a:account}). Use the following line to display a popup window with debugging information: sforce.trace=true.execute("myClass".sObject("Account"). If a namespace is defined. and lists of primitives or sObjects. . and can be quickly understood by those who are familiar with them. They are stored in the application under Your Name > Setup > Develop > Apex Classes. • • • • • • • • • • • Understanding Classes Interfaces and Extending Classes Keywords Annotations Classes and Casting Differences Between Apex Classes and Java Classes Class Definition Creation Class Security Enforcing Object and Field Permissions Namespace Prefix Version Settings A class is a template or blueprint from which Apex objects are created. class methods or variables can be invoked by other Apex code. user-defined methods. or through the SOAP API (or AJAX Toolkit) for methods that have been designated with the webService keyword. Objects. exception types. Once successfully saved. and static initialization code.Chapter 4 Classes. the class concepts described here are modeled on their counterparts in Java. variables. • • • • • • • Understanding Classes—more about creating classes in Apex Interfaces and Extending Classes—information about interfaces Keywords and Annotations—additional modifiers for classes. and Interfaces In this chapter . In most cases.. Classes consist of other classes. methods or variables Classes and Casting—assigning a class of one data type to another Differences Between Apex Classes and Java Classes—how Apex and Java differ Class Definition Creation and Class Security—creating a class in the Salesforce user interface as well as enabling users to access a class Namespace Prefix and Version Settings—using a namespace prefix and versioning Apex classes 101 . that is. that is. For example. An instance of the PurchaseOrder class is a specific purchase order that you send or receive.html Defining Apex Classes In Apex. or notifying a customer. and whether it was flagged as important. A class can contain variables and methods. The behavior of a PurchaseOrder object—what it can do—includes checking inventory. a class defined within another class. Since these variables are associated with a class and are members of it. An object is an instance of a class. and so on) 3. things that an object knows about itself. For more general information on classes. they are commonly referred to as member variables. the PurchaseOrder class describes an entire purchase order. the date and time it was created. Optional definition modifiers (such as virtual. Objects. objects. shipping a product. and everything that you can do with a purchase order. such as getOtherQuotes or copyLineItems. Required: The keyword class followed by the name of the class 4. All objects have state and behavior. you can define top-level classes (also called outer classes) as well as inner classes.sun. specify the following: 1. Methods are used to control behavior. 2. For example: public class myOuterClass { // Additional myOuterClass code here class myInnerClass { // myInnerClass code here } } To define a class. and things that an object can do. Optional extensions and/or implementations Use the following syntax for defining classes: private | public | global [virtual | abstract | with sharing | without sharing | (none)] class ClassName [implements InterfaceNameList | (none)] [extends ClassName | (none)] { // The body of the class } 102 . An interface is like a class in which none of the methods have been implemented—the method signatures are there. The state of a PurchaseOrder object—what it knows—includes the user who sent it. another class must implement it by providing a body for all of the methods contained in the interface. Variables are used to specify the state of an object. see http://java. and interfaces. abstract.Classes. such as the object's Name or Type. and Interfaces Understanding Classes Understanding Classes As in Java. you can create classes in Apex. You can only have inner classes one level deep. Access modifiers: • • You must use one of the access modifiers (such as public or global) in the declaration of a top-level class.com/docs/books/tutorial/java/concepts/index. but the body of each method is empty. To use an interface. A class is a template or blueprint from which objects are created. You do not have to use an access modifier in the declaration of an inner class. You cannot override a public or protected virtual method of a global class of an installed managed package. only by this section of code. For more information about method and variable access modifiers. Note: • • • You cannot add an abstract method to a global class after the class has been uploaded in a Managed . top-level class must also be defined as global. } // Static initialization (can be included where the variable is defined) static { MY_INT = 2. Extended Class Example The following is an extended example of a class. The with sharing and without sharing keywords specify the sharing mode for this class. The public access modifier declares that this class is visible in your application or namespace.Released package is virtual.Released package version. see Interfaces and Extending Classes on page 117. see Developing Apex in Managed Packages on page 220. This restriction means that Apex does not support multiple inheritance. A class can implement multiple interfaces. Objects. This keyword can only be used with inner classes.outer class level only public static Integer getInt() { return MY_INT. The global access modifier declares that this class is known by all Apex code everywhere. // Top-level (outer) class must be public or global (usually public unless they contain // a Web Service. For more information about interfaces. the method that you can add to it must also be virtual and must have an implementation. methods that only have their signature declared and no body defined. showing all the features of Apex classes. You cannot override a method with the override keyword unless the class has been defined as virtual. it is considered private. // Static method . if you don't specify an access modifier for an inner class. then they must be global) public class OuterClass { // Static final variable (constant) – outer class level only private static final Integer MY_INT. For more information. If a method or inner class is declared as global. and Interfaces Extended Class Example • • • • • • The private access modifier declares that this class is only known locally. that is.Classes. } // Member variable for outer class 103 . // Non-final static variable . see Using the with sharing or without sharing Keywords on page 124. see Access Modifiers on page 111.use this to communicate state across triggers // within a single request) public static String sharedState. The keywords and concepts introduced in the example are explained in more detail throughout this chapter. that is. For more information about managed packages. The interface names in the list are separated by commas. If the class in the Managed . All classes that contain methods defined with the webService keyword must be declared as global. but only extend one existing class. the outer. The virtual definition modifier declares that this class allows extension and overrides. This is the default access for inner classes—that is. The abstract definition modifier declares that this class contains abstract methods. and Interfaces Extended Class Example private final String m. No constructor is needed since // parent class has a no-argument constructor public abstract class AbstractChildClass extends InnerClass { // Override the parent class method with this signature. // This method references member variables (with and without the "this" prefix) public Integer method2(Integer i) { return this. an implicit. in turn. } // Because no constructor is explicitly defined in this outer class.length().s = 'x'.length(). } // Constructor that assigns a final variable value public InnerClass(String s2) { this.these are always // public or global depending on the interface visibility void myMethod(). } // Instance method that implements a method from MyInterface. public constructor exists // Inner interface public virtual interface MyInterface { // No access modifier is necessary for interface methods . // Explicit no argument constructor InnerClass() { // This invokes another constructor that is defined later this('none'). // This class implements an interface that. } // Interface extension interface MySecondInterface extends MyInterface { Integer method2(Integer i). } } // Abstract class (that subclasses the class above). // no-argument. } // Inner class . // Instance initialization block . // Consequently the class must implement all methods. private final String s2. } // Inline initialization (happens after the block above executes) private final Integer i = s. // or in a constructor { m = 'a'.can be done where the variable is declared.Classes. public virtual void myMethod() { /* does nothing */ } // Implementation of the second interface method above. extends another interface.s2 = s2. public virtual class InnerClass implements MySecondInterface { // Inner member variables private final String s. // Must use the override keyword 104 . // Inner instance initialization block (this code could be located above) { this. // Because it is declared virtual it can be overridden by a subclass.i + s. Objects.because it is virtual it can be extended. as well as static initialization code blocks Member variables and methods for the top-level class Classes with no user-defined constructor — these have an implicit.Classes. and Interfaces Extended Class Example public override void myMethod() { /* do something else */ } // Same name as parent class method.subclasses of this class must implement this method abstract Integer abstractMethod().note that visibility // cannot be restricted by a sub-class public override Integer abstractMethod() { return 5. its associated sub-interface) by implementing public versions of the method signatures An inner class constructor definition and invocation An inner class member variable and a reference to it using the this keyword (with no arguments) An inner class constructor that uses the this keyword (with arguments) to invoke a different constructor 105 . } } // Exception inner class public virtual class MyException extends Exception { // Exception class member variable public Double d. therefore. but different signature. marked as protected protected void doIt() {} } // Exception classes can be abstract and implement interfaces public abstract class MySecondException extends Exception implements MyInterface { } } This code example illustrates: • • • • • • • • • • • A top-level class definition (also called an outer class) Static variables and static methods in the top-level class. } // Complete the abstract class by implementing its abstract method public class ConcreteChildClass extends AbstractChildClass { // Here we expand the visibility of the parent method . // Exception class constructor MyException(Double d) { this. } // Exception class method. } } // A second sub-class of the original InnerClass public class AnotherChildClass extends InnerClass { AnotherChildClass(String s) { // Explicitly invoke a different super constructor than one with no arguments super(s). // This is a different method (displaying polymorphism) so it does not need // to use the override keyword protected void method2() {} // Abstract method .d = d. Objects. no-argument constructor An interface definition in the top-level class An interface that extends another interface Inner class definitions (one level deep) within a top-level class A class that implements an interface (and. assertEquals(2. as with Java. System.assertEquals(2.InnerClass ic2 = mi instanceof OuterClass.InnerClass('x'). specify the following: • • Optional: Modifiers. and assign it a value that is of // a type that implements that interface OuterClass.getInt().method2(1)). // Illegal . Class extension and an abstract class Methods that override base class methods (which must be declared virtual) The override keyword for methods that override subclass methods Abstract methods and their implementation by concrete sub-classes The protected access modifier Exceptions as first class objects with members.InnerClass)mi : null.AbstractChildClass(). // Construct the outer type OuterClass o = new OuterClass().getInt()). ic. // Illegal – cannot access a static method through an instance // o. as well as with anonymous blocks in curly braces ({}). Note that these execute with every construction in the order they appear in the file. such as String or Boolean.Classes. // Construct instances of abstract class children System. // Define a variable with an interface data type. methods.InnerClass ic = new OuterClass.ConcreteChildClass().assert(ic2 != null). and constructors This example shows how the class above can be called by other Apex code: // Construct an instance of an inner concrete class.InnerClass ? (OuterClass. 106 . with a user-defined constructor OuterClass.assertEquals(5.MyInterface mi = ic. new OuterClass.abstractMethod()). System.ConcreteChildClass().cannot construct an abstract class // new OuterClass.method2().cannot call protected method externally // new OuterClass. as well as static. // Use instanceof and casting as usual OuterClass. OuterClass. Required: The data type of the variable. // Call user-defined methods in the class System. This code example illustrates: • • • • Construction of the outer class Construction of an inner class and the declaration of an inner interface type A variable declared as an interface type can be assigned an instance of a class that implements that interface Casting an interface variable to be a class type that implements that interface (after verifying this using the instanceof operator) Declaring Class Variables To declare a variable. such as public or final. Objects. // Illegal . and Interfaces Declaring Class Variables • • • • • • • Initialization code outside of constructors — both where variables are defined. and enclosed in parentheses (). Optional: The value of the variable. Required: A list of input parameters for the method. } As in Java. For example: public static Integer getInt() { return MY_INT. such as String or Integer. such as DML insert statements that initialize sObject record IDs. Note that user-defined methods: • • • • Can be used anywhere that system methods are used. See Apex Data Manipulation Language (DML) Operations on page 257. each preceded by its data type. such as public or protected. separated by commas. Required: The data type of the value returned by the method. Required: The body of the method. Defining Class Methods To define a method. Apex parses methods in two phases. Use the following syntax when defining a variable: [public | private | protected | global | final] [static] data_type variable_name [= value] For example: private static final Integer MY_INT. 107 . All the code for the method. A method can only have 32 input parameters. is contained here.Classes. Can be recursive. enclosed in braces {}. methods that return values can also be run as a statement if their results are not assigned to another variable. so forward declarations are not needed. Use void if the method does not return a value. use a set of empty parentheses. Objects. and Interfaces Defining Class Methods • • Required: The name of the variable. Use the following syntax when defining a method: (public | private | protected | global ) [override] [static] data_type method_name (input parameters) { // The body of the method } Note: You can only use override to override methods in classes that have been defined as virtual. If there are no parameters. including any local variable declarations. private final Integer i = 1. Can have side effects. Can refer to themselves or to methods defined later in the same class or anonymous block. specify the following: • • • • Optional: Modifiers. When the method returns. The following are examples of passing primitive and non-primitive data type arguments into methods. are also passed into methods by value. For more information on data conversion. the value of the original variable. // The value of the msg variable didn't // change. it then seeks an approximate match using type coercion rules. The debugStatusMessage method in this example creates a String variable. System. an assert verifies that the contents of the original List 108 . 'Original value'). the createTemperatureHistory method creates a variable. are passed into methods by value. For example. one with a single Integer parameter and one with two Integer parameters. The called method fills this list with Integer values representing rounded temperature values. a parse-time exception is generated. • When using void methods that have side effects. First. Depending on whether the method is called with one or two Integers. the changes to the arguments are lost. However. However. It also shows that the List argument can’t be modified to point to another List object. msg. such as sObjects. all primitive data type arguments. see Understanding Rules of Conversion on page 46. public class PassPrimitiveTypeExample { public static void debugStatusMessage() { String msg = 'Original value'. This is the same as in Java. It then passes this variable as an argument to another method. the values of the object's fields can be changed in the method. a method named foo can be implemented in two ways. Objects.Classes. such as Integer or String. fillMe.debug('Here is a note for the log. user-defined methods are typically executed as stand-alone procedure statements in Apex code. Example: Passing Primitive Data Type Arguments This example shows how a primitive argument of type String is passed by value into another method. msg. the passed-in argument still references the same object as before the method call and can't be changed to point to another object. and when the method returns. which modifies the value of this String.'). it is passed by value. the Apex parser selects the appropriate implementation to execute. } public static void processString(String s) { s = 'Modified value'. and Interfaces Defining Class Methods • Can be polymorphic. If the parser cannot find an exact match.assertEquals(msg. it is still the old value. } } Example: Passing Non-Primitive Data Type Arguments This example shows how a List argument is passed by value into another method and can be modified. For example: System. Non-primitive data type arguments. Note: If the parser finds multiple approximate matches. since String is a primitive type. When the method returns. processString(msg). that is a List of Integers and passes it to a method. This means that any changes to the arguments exist only within the scope of the method. • Can have statements where the return values are run as a statement if their results are not assigned to another variable. and assigns it a value. An assert statement verifies that the value of msg is still the old value. Passing Method Arguments By Value In Apex. This means that when the method returns. is unchanged. List<Integer> createMe = new List<Integer>().add(80). an implicit.assertEquals(createMe. } public static void referenceNew(List<Integer> m) { // Assign argument to a new List of // five temperature values. no-argument.0). referenceNew(createMe). m = new List<Integer>{55.size(). the original createMe variable doesn’t point to the new List but still points to the original List.size(). m. 60. using the following class: public class TestObject { // The no argument constructor public TestObject() { // more code here } } A new object of this type can be instantiated with the following code: TestObject myTest = new TestObject(). and Interfaces Using Constructors variable has changed and now contains five values. For example. The syntax for a constructor is similar to a method. } public static void reference(List<Integer> m) { // Add rounded temperatures for the last five days. 109 . If a class does not have a user-defined constructor. reference(fillMe).5). and passes it to another method.add(82).assertEquals(fillMe. public class PassNonPrimitiveTypeExample { public static void createTemperatureHistory() { List<Integer> fillMe = new List<Integer>(). System. Next. public one is used. m. the example creates a second List variable.Classes. Objects. createMe. The called method assigns the passed-in argument to a newly created List that contains new Integer values. // The list is modified and contains five items // as expected.add(75). but it differs from a method definition in that it never has an explicit return type and it is not inherited by the object created from it. 59. not the new list // that the method created. m. When the method returns. m. // The list is not modified because it still points // to the original list. you must use the new keyword in order to instantiate an object from that class. which is empty.add(70). m.add(68). 63}. You do not need to write a constructor for every class. using that constructor. System. 62. } } Using Constructors A constructor is code that is invoked when an object is created from the class blueprint. After you write the constructor for a class. An assert verifies that createMe contains no values. . It also illustrates how one constructor calls another constructor using the this(. or Account. you can then use that constructor to create an object using those arguments. you are defining a new data type. public class TestObject2 { private static final Integer DEFAULT_SIZE = 10. String email) {} } When you define a new class. that is. all of the constructors are possible: public class Leads { // First a no-argument constructor public Leads () {} // A constructor with one argument public Leads (Boolean call) {} // A constructor with two arguments public Leads (String email. so this is legal public Leads (Boolean call.. Boolean call) {} // Though this constructor has the same arguments as the // one above. Integer size. a constructor can be overloaded. } } New objects of this type can be instantiated with the following code: TestObject2 myObject1 = new TestObject2(42). Every constructor that you create for a class must have a different argument list. You can use class name in any place you can use other data type names. you no longer have access to the default.. You must create your own.Classes. and Interfaces Using Constructors If you write a constructor that takes arguments.) syntax. 110 . The following example illustrates a class with two constructors: one with no arguments and one that takes a simple Integer argument. Once you create a constructor for a class. If you define a variable whose type is a class. such as String. //Constructor with no arguments public TestObject2() { this(DEFAULT_SIZE). Boolean. Objects. TestObject2 myObject2 = new TestObject2(). there can be more than one constructor for a class. they are in a different order. In Apex. In the following example. also know as constructor chaining. any object you assign to it must be an instance of that class or subclass.) calls the one argument constructor } // Constructor with one argument public TestObject2(Integer ObjectSize) { size = ObjectSize. // Using this(.. no-argument public constructor. each having different parameters. If you create a constructor that takes arguments. you must include one in your code. and you still want to use a no-argument constructor. either in the SOAP API or by other Apex code. You can change the level of visibility by using the following access modifiers: private This is the default. the public access modifier is not the same as it is in Java. they are not as useful in smaller portions of Apex. public. protected This means that the method or variable is visible to any inner classes in the defining Apex class. if at all. the method or variable is private. This access modifier should be used for any method that needs to be referenced outside of the application. protected. Note: We recommend using the global access modifier rarely.Classes. They are always global. see Interfaces and Extending Classes on page 117. Cross-application dependencies are difficult to maintain. If you declare a method or variable as global. For more information. This was done to discourage joining applications. public. to keep the code for each application separate. You can only use this access modifier for instance methods and member variables. To use the private. If you do not specify an access modifier. you must also declare the class that contains it as global. global This means the method or variable can be used by any Apex code that has access to the class. While triggers and anonymous blocks can also use these access modifiers. By default. use the following syntax: [(none)|private|protected|public|global] declaration 111 . declaring a method as global in an anonymous block does not enable you to call it from outside of that code. you need to use the global access modifier. and means that the method or variable is accessible only within the Apex class in which it is defined. a method or variable is visible only to the Apex code within the defining class. Note: In Apex. You must explicitly specify a method or variable as public in order for it to be available to other classes in the same application namespace (see Namespace Prefix). or global access modifiers. and Interfaces Access Modifiers Access Modifiers Apex allows you to use the private. see Defining Apex Classes on page 102. protected. In Apex. not just the Apex code in the same application. For more information on class access modifiers. if you want to make something public like it is in Java. Objects. just like Java. For example. public This means the method or variable can be used by any Apex in this application or namespace. Note that it is strictly more permissive than the default (private) setting. Note: Interface methods have no access modifiers. and global access modifiers when defining methods and variables. or initialization code are associated with a class. This includes any static initialization code blocks. Because a static method is only associated with a class. A static method or variable does not require an instance of the class in order to run. and initialization code are associated with a particular object and have no definition modifier. all triggers that are spawned by the same request can communicate with each other by viewing and updating static variables in a related class. When you declare a method or variable as static. it cannot access any instance member variable values of its class. member variables. When you declare instance methods. All static member variables in a class are initialized before any object of the class is created. All local variables should be initialized before they are used. All of these are run in the order in which they appear in the class. They are not static across the server. Objects. public string gets1() { return this. A recursive trigger might use the value of a class variable to determine when to exit the recursion. variables. Static variables aren't transmitted as part of the view state for a Visualforce page. you can have static methods. an instance of that item is created with every object instantiated from the class. and are only allowed in outer classes. Local variables are associated with the block of code in which they are declared. and Interfaces Static and Instance For example: private string s1 = '1'.Classes. For example. Static variables are only static within the scope of the request. and local variables: • Static methods. or initialization code. } Using Static Methods and Variables You can only use static methods and variables with outer classes. variables. or across the entire organization. Instance methods. } Static and Instance In Apex. if (myCondition) { integer localVariable = 10. Suppose you had the following class: public class p { public static boolean firstRun = true. Apex classes can’t be static. Inner classes have no static methods or variables. member variables. member variables. Use static variables to store information that is shared within the confines of the class.s1. You can also have instance methods. • • The following is an example of a local variable whose scope is the duration of the if code block: Boolean myCondition = true. All instances of the same class share a single copy of the static variables. } 112 . it's initialized only once when a class is loaded. and initialization code. and initialization code (which have no modifier). Static methods are generally used as utility methods and never depend on a particular instance member variable value. The same is true for instance methods: if M() is a static method then x.0 or earlier.isDelete){ if(p.M() is not legal.0 and later.isBefore){ if(Trigger.M(). public class Plotter { // This inner class manages the points class Point { Double x.com API version 20. } } 113 . but not within a method. but there is no implicit pointer to an instance of the outer class (using the this keyword).old[0]. but do not require the static keyword. Note: For Apex saved using Salesforce. For Apex saved using Salesforce.firstRun=false. So if class C has a static variable S. Instance methods usually use instance member variables to affect the behavior of the method. Suppose you wanted to have a class that collects two dimensional points and plot them on a graph. Note that static variable values are reset between batches.addError('Before Account Delete Error').y = y.x = x. If a local variable is named the same as the class name.Classes.S and C. } Double getYCoordinate() { return y. Inner classes can have instance member variables like outer classes.com API version 21.firstRun){ Trigger. Double y. no further splits of API batches occur. Point(Double x. that is. by an object. p. } Double getXCoordinate() { return x. Double y) { this. your code should refer to those static identifiers using the class: C. making use of member variables to hold the list of points and an inner class to manage the two-dimensional list of points. Inner classes behave like static Java inner classes. the batch of 200 records to process is further split into batches of 100 records. Using Instance Methods and Variables Instance methods and member variables are used by an instance of a class. and x is an instance of C. } } } } Class static variables cannot be accessed through an instance of that class. The following skeleton class illustrates this. Instead. but governor limits are not. if an API call causes a trigger to fire.S is not a legal expression. after undelete) { if(Trigger. Instance member variables are declared inside a class. this. and Interfaces Static and Instance A trigger that uses this class could then selectively fail the first run of the trigger: trigger t1 on Account (before delete. then x. Objects. after delete. Do not use static variables to track state information between batches. these static methods and variables are hidden. They can appear anywhere in the code body. a static initialization code block is only initialized once on the first use of the class. Static initialization code is a block of code preceded with the keyword static: static { //code body } Similar to other static code. 114 . For example: public class MyClass { class RGB { Integer red. } // The following method takes the list of points and does something with them public void render() { } } Using Initialization Code Instance initialization code is a block of code in the following form that is defined in a class: { //code body } The instance initialization code in a class is executed every time an object is instantiated from that class. RGB>(). the same as in Java. The code blocks are executed in the order in which they appear in the file. Integer green.Classes.add(new Point(x. such as a map of values. However. most of the time you should either give the variable a default value or use the body of a constructor to do initialization and not use instance initialization code. this. RGB(Integer red. These code blocks run before the constructor.red = red. y)). RGB> colorMap = new Map<String. } } static Map<String. this. you can use an instance initialization code block to initialize instance variables. public void plot(Double x. If you do not want to write your own constructor for a class. You can use static initialization code to initialize static final variables and to declare any information that is static.blue = blue. A class can have any number of either static or instance initialization code blocks. and Interfaces Static and Instance List<Point> points = new List<Point>(). Double y) { points. Objects. Integer blue) { this. Integer green. Integer blue.green = green. new RGB(255. such as Integer. The code in a set accessor executes when the property is assigned a new value. or they can expose data that is retrieved from some other source. A property with only a set accessor is considered write-only. see Access Modifiers on page 111. return_type is the type of the property. use the following syntax in the body of a class: Public class BasicClass { // Property declaration access_modifier return_type property_name { get { //Get accessor code block } set { //Set accessor code block } } } Where: • access_modifier is the access modifier for the property. and so on. } set { prop = value. To declare a property. A property with only a get accessor is considered read-only. protected. such as another class. property_name is the name of the property For example.put('red'. Properties can be used in many different ways: they can validate data before a change is made. representing a get accessor and a set accessor: • • The code in a get accessor executes when the property is read. you can do additional things in your code to a property value before it is accessed or returned. sObject. colorMap. colorMap. 255)). virtual. 0)). 0. such as altering the value of other member variables. override and transient. The property is public. see Data • • Types on page 26.put('cyan'. the following class defines a property named prop. A property with both accessors is read-write. The property returns an integer data type. Objects.put('magenta'. All modifiers that can be applied to variables can also be applied to properties. private. new RGB(255. For more information. Property definitions include one or two code blocks. they can prompt an action when data is changed. new RGB(0. 255. and Interfaces Apex Properties static { colorMap.Classes. } } } 115 . 255)). static. abstract. global. } } Apex Properties An Apex property is similar to a variable. public class BasicProperty { public integer prop { get { return prop. Double. however. For more information on access modifiers. These include: public. 0. prop = 5. Objects.prop == 5). They can be declared as read-only. read-write. The set accessor is similar to a method whose return type is void. It must return a value of the property type.assert(bp. Apex properties are based on their counterparts in C#. Instead.} 116 . the system passes an implicit argument to the setter called value of the same data type as the property. the property's accessor methods execute in a static context. see Using Automatic Properties on page 116. For more information. } public string MyWriteOnlyProp { set. This means that the accessors do not have access to non-static member variables defined in the class. // Calls set accessor System.Classes. the set accessor is invoked with an argument that provides the new value. You do not need to create supporting members for storing values. When you assign a value to the property. exercising the get and set accessors: BasicProperty bp = new BasicProperty(). Properties cannot be defined on interface. Executing the get accessor is the same as reading the value of the variable. or write-only.MyReadWriteProp = 5. and Interfaces Apex Properties The following code segment calls the class above. We recommend that your get accessor should not change the state of the object that it is defined on. set. When the set accessor is invoked. } } The following code segment exercises these properties: AutomaticProperty ap = new AutomaticProperty(). with the following differences: ◊ Properties provide storage for values directly. The get accessor must end in a return statement. public integer NonStaticMember.assert(MyWriteOnlyProp == 5). Automatic properties allow you to write more compact code that is easier to debug and maintain. } public double MyReadWriteProp { get. // This produces a compile error: not readable Using Static Properties When a property is declared as static. The following example creates three automatic properties: public class AutomaticProperty { public integer MyReadOnlyProp { get. // Calls get accessor Note the following: • • • • • • • • The body of the get accessor is similar to that of a method.MyReadOnlyProp = 5. ◊ It is possible to create automatic properties in Apex. you can leave get and set accessor code blocks empty to define an automatic property. // This produces a compile error: not writable ap. ap. public static integer MyGoodStaticProp { get{return MyGoodStaticProp. // No error System. Using Automatic Properties Properties do not require additional code in their get or set accessor code blocks. bp. The following example creates a class with both static and instance properties: public class StaticProperty { public static integer StaticMember. public class PurchaseOrders { // An interface that defines what a purchase order looks like in general public interface PurchaseOrder { // All other functionality excluded 117 . public set. For example. } // Y can be globally read but only written within a class global integer Y { get. Both are a type of purchase order. } } Interfaces and Extending Classes An interface is like a class in which none of the methods have been implemented—the method signatures are there. Defining an interface is similar to defining a new class. Objects. this modifier overrides the access modifier of the property. and others that come from their employees.Classes. set. // The following produces a system error: a static variable cannot be // accessed through an object instance // sp. Suppose you needed a method to provide a discount. another class must implement it by providing a body for all of the methods contained in the interface. a company might have two types of purchase orders. the individual accessor cannot be defined as global.MyGoodStaticProp = 5. but the body of each method is empty. The following class definition shows additional examples: global virtual class PropertyVisibility { // X is private for read and public for write public integer X { private get. } // Z can be read within the class but only subclasses can set it public integer Z { get. The amount of the discount can depend on the type of purchase order.} } } The following code segment calls the static and instance properties: StaticProperty sp = new StaticProperty(). This way you can have different implementations of a method based on your specific application.MyGoodStaticProp = 5. protected set. Using Access Modifiers on Property Accessors Property accessors can be defined with their own access modifiers. } public integer MyGoodNonStaticProp { get{return NonStaticMember. and Interfaces Interfaces and Extending Classes } // The following produces a system error // public static integer MyBadStaticProp { return NonStaticMember. Interfaces can provide a layer of abstraction to your code. In the following example the focus is only on the discount aspect of a purchase order. If an accessor includes its own access modifier. They separate the specific implementation of a method from the declaration for that method. The access modifier of an individual accessor must be more restrictive than the access modifier on the property itself. ones that come from customers. To use an interface. For example. You can model the general concept of a purchase order as an interface and have specific implementations for customers and employees. if the property has been defined as public. // The following does not produce an error StaticProperty. An interface can extend another interface.Released package version. // It’s worth it being an employee! 10% discount } } } Note the following about the above example: • • • The interface PurchaseOrder is defined as a general prototype. and Interfaces Custom Iterators Double discount(). any class that implements an interface must define all of the methods contained in the interface. When you define a new interface. If you define a variable whose type is an interface. The CustomerPurchaseOrder class implements this interface. but with a // different discount public class EmployeePurchaseOrder extends CustomerPurchaseOrder{ public override Double discount() { return . and you must provide some means of traversing the collection. A class extends another class using the keyword extends. The employee version of the purchase order extends the customer version. Custom Iterators An iterator traverses through every item in a collection. that is. Iterators can also be used if you have multiple SELECT statements. As with classes. but it can implement more than one interface.debug(count). count is incremented by 1 every time the loop is executed (count++) : while (count < 11) { System. For example. it must provide a definition for the discount method. or a sub-interface data type. // Flat 5% discount } } // Employee purchase order extends Customer purchase order. A class can only extend one other class.Classes. Objects.10. 118 . } // One implementation of the interface for customers public virtual class CustomerPurchaseOrder implements PurchaseOrder { public virtual Double discount() { return .05. any object you assign to it must be an instance of a class that implements the interface. Note: You cannot add a method to a global interface after the class has been uploaded in a Managed . when an interface extends another interface. count++. all the methods and properties of the extended interface are available to the extending interface. an iterator. therefore. As with Java. You can use an interface name in any place you can use another data type name. in a while loop in Apex. you define a condition for exiting the loop. In the following example. } Using the Iterator interface you can create a custom set of instructions for traversing a List through a loop. you are defining a new data type. This is useful for data that exists in sources outside of Salesforce that you would normally define the scope of using a SELECT statement. See also Classes and Casting on page 134. Methods defined within an interface have no access modifiers and contain just their signature. next()). It creates a reference to the iterator that you can then use to traverse the data structure. next All methods in the Iterator interface must be declared as global or public. you must create an Apex class that implements the Iterator interface.debug(x. The Iterable interface has the following method: Name iterator Arguments Returns Iterator class Description Returns a reference to the iterator for this interface. } Iterators are not currently supported in for loops.').hasNext()){ system. Objects. but instead want to create your own data structure. and Interfaces Custom Iterators Using Custom Iterators To use custom iterators. NumberOfEmployees FROM Account WHERE Name = 'false']. You can only use a custom iterator in a while loop. set.} Integer i {get. 119 .Classes. you can use the Iterable interface to generate the data structure. In the following example a custom iterator iterates through a collection: global class CustomIterable implements Iterator<Account>{ List<Account> accs {get. false otherwise. Returns the next item in the collection. The Iterator interface has the following instance methods: Name hasNext Arguments Returns Boolean Any type Description Returns true if there is another item in the collection being traversed. Using Custom Iterators with Iterable If you do not want to use a custom iterator with a list. For example: IterableString x = new IterableString('This is a really cool test.size()) { return false. while(x. set. } global boolean hasNext(){ if(i >= accs.} public CustomIterable(){ accs = [SELECT Id. i = 0. The iterator method must be declared as global or public. Name. for(Account a : scope){ a. return accs[i-1].batchableContext info){ return new foo(). accsToUpdate. } } global Account next(){ // 8 is an arbitrary // constant in this example // that represents the // maximum size of the list. } } The following calls the above code: global class foo implements iterable<Account>{ global Iterator<Account> Iterator(){ return new CustomIterable().Classes. } global void finish(Database. } } The following is a batch job that uses an iterator: global class batchClass implements Database.batchableContext info.NumberOfEmployees = 69. Objects.} i++. List<Account> scope){ List<Account> accsToUpdate = new List<Account>(). if(i == 8){return null. } global void execute(Database.batchableContext info){ } } Keywords Apex has the following keywords available: • • • • • • final instanceof super this transient with sharing and without sharing 120 .Name = 'true'. } update accsToUpdate. a.add(a). and Interfaces Keywords } else { return true.batchable<Account>{ global Iterable<Account> start(Database. or with other variable declarations.'. public SuperClass() { mySalutation = 'Mr. and Interfaces Using the final Keyword Using the final Keyword You can use the final keyword to modify variables. you can override constructors and methods from the parent class.Classes. By using super. If (Reports. } Else { // Do something with the non-custom-report. For example. myLastName = 'Vonderburg'. Objects. However. You must assign a value to it in one of these two places. mark a variable as both static and final (see Constants on page 48).get(0). } Using the super Keyword The super keyword can be used by classes that are extended from virtual or abstract classes. Using the instanceof Keyword If you need to verify at runtime whether an object is actually an instance of a particular class. public String myLastName. You could add the following check to the Report class in the classes and casting example before you cast the item back into a CustomReport object. use the instanceof keyword. String firstName. 121 . myFirstName = firstName. either when you declare a variable or in initialization code. public String myFirstName. The instanceof keyword can only be used to verify if the target type in the expression on the right of the keyword is a viable alternative for the declared type of the expression on the left. Static final variables can be changed in static initialization code or where defined. they are not shared across requests. myFirstName = 'Carl'. } public SuperClass(String salutation.get(0) instanceof CustomReport) { // Can safely cast it back to a custom report object CustomReport c = (CustomReport) Reports. Non-final static variables are used to communicate state at the class level (such as state between triggers). Use the virtual keyword if you need to override a method or class. To define a constant. You cannot use the final keyword in the declaration of a class or method. if you have the following virtual class: public virtual class SuperClass { public String mySalutation. constructors. Methods and classes are final by default. Member final variables can be changed in initialization code blocks. • • • • • • Final variables can only be assigned a value once. This means they cannot be overridden. String lastName) { mySalutation = salutation. 122 . and Interfaces Using the this Keyword myLastName = lastName. Best Practices for Using the super Keyword • • Only classes that are extending from virtual or abstract classes can use super. } public virtual void printName() { System.getFirstName()). without parenthesis. You can only use super in methods that are designated with the override keyword. } } You can create the following class that extends Superclass and overrides its printName method: public class Subclass extends Superclass { public override void printName() { super. 'Brenda'. } Now. For example: public class myTestThis { string s. Use this form of the this keyword to access instance variables and methods. to represent the current instance of the class in which it appears. the class myTestThis declares an instance variable s.printName is My name is Mr.printName is My name is Madam Clapentrap. Vonderburg. But you can call me Carl.debug('But you can call me ' + super. } } The expected output when calling Subclass.debug('My name is ' + mySalutation + myLastName). Using the this Keyword There are two different ways of using the this keyword. 'Clapentrap'). But you can call me Brenda. You can also use super to call constructors. System. } } In the above example. The initialization code populates the variable using the this keyword. the expected output of Subclass. } public virtual String getFirstName() { return myFirstName. Add the following constructor to SubClass: public Subclass() { super('Madam'. { this.printName(). You can use the this keyword in dot notation.Classes. Objects.s = 'TestString'. public testThis() { this('None'). or classes that implement the Batchable or Schedulable interface. A common use case for the transient keyword is a field on a Visualforce page that is needed only for the duration of a page request. in one constructor. <apex:page controller="ExampleController"> T1: {!t1} <br/> T2: {!t2} <br/> <apex:form> <apex:commandLink value="refresh"/> 123 . JSONParser class instances. such as a collection of Savepoints Most of the objects generated by system methods. You can also use the transient keyword in Apex classes that are serializable. and shouldn't be transmitted as part of the view state for a Visualforce page.getGlobalDescribe. which has been deserialized from the view state. but should not be part of the page's view state and would use too many system resources to be recomputed many times during a request. Some Apex objects are automatically considered transient. Using the transient Keyword Use the transient keyword to declare instance variables that can't be saved. // This constructor calls the first constructor using the this keyword. } } When you use the this keyword in a constructor to do constructor chaining. The non-transient date continues to have its original value.Classes. see JSON Support on page 389. Declaring variables as transient reduces view state size. use the this keyword with parentheses. call another constructor. In this format. and Interfaces Using the transient Keyword Or you can use the this keyword to do constructor chaining. The following example contains both a Visualforce page and a custom controller. you can use transient in classes that define the types of fields declared in the serializable classes. namely in controllers. public testThis(string s2) { } // Second constructor for the class. For more information. It does not require a parameter. so it remains the same. For example: Transient Integer currentTotal. controller extensions. that is. it must be the first statement in the constructor. that is. In addition. Objects. These objects include the following: • • • • • PageReferences XmlStream classes Collections automatically marked as transient only if the type of object that they hold is automatically marked as transient. It requires a string parameter. Static variables also don't get transmitted through the view state. Clicking the refresh button on the page causes the transient date to be updated because it is being recreated each time the page is refreshed. For example: public class testThis { // First constructor for the class. such as Schema. their value does not get saved as part of the page's view state. which can be restricted by permissions.now(). However. Apex code always has access to all fields and objects in an organization. or organization-wide defaults. return '' + t1.com online help.) Note: Enforcing sharing rules by using the with sharing keyword doesn’t enforce the user's permissions and field-level security. } public String getT2() { if (t2 == null) t2 = System. Most of the time. transient DateTime t2. They should be particularly careful with Web services. Note: The only exceptions to this rule are Apex code that is executed with the executeAnonymous call. executeAnonymous always executes using the full permissions of the current user. see Anonymous Blocks on page 98. field-level security.Classes. the current user's permissions. } } Using the with sharing or without sharing Keywords Apex generally runs in system context. Because these rules aren't enforced. but execute in system context once they are initiated. ensuring that code won’t fail to run because of hidden fields or objects for a user. you can also specify that particular Apex classes should enforce the sharing rules that apply to the current user. field-level security. system context provides the correct behavior for system-level operations such as triggers and Web services that need access to all data in an organization. Use the with sharing keywords when declaring a class to enforce the sharing rules that apply to the current user. For more information on executeAnonymous.now(). Objects. For example: public with sharing class sharingClass { // Code here } Use the without sharing keywords when declaring a class to ensure that the sharing rules for the current user are not enforced. return '' + t2. see the Salesforce. For example: public without sharing class noSharing { // Code here 124 . public String getT1() { if (t1 == null) t1 = System. developers who use Apex must take care that they don't inadvertently expose sensitive data that would normally be hidden from users by user permissions. and Interfaces Using the with sharing or without sharing Keywords </apex:form> </apex:page> public class ExampleController { DateTime t1. and sharing rules aren’t taken into account during code execution. that is. (For more information on sharing rules. Account a = [SELECT . // This call into CWith operates with enforced sharing rules // for the context user. . . constructors. and Interfaces Using the with sharing or without sharing Keywords } If a class is not declared as either with or without sharing. } public class CInner { // All code in this class executes with the same sharing context // as the code that calls it. . } { . public static void m() { . } public c() { . then sharing is enforced for the called class. . . public static void m() { . Classes inherit this setting from a parent class when one class extends or implements another. CWith. and methods. // When the call finishes. . } public class CInnerWithOut exends CWithout { // All code in this class ignores sharing rules because // this class extends a parent class that ignores sharing rules. ]. . Objects. .m(). } static { . . . // Inner classes are separate from outer classes. For example: public with sharing class CWith { // All code in this class operates with enforced sharing rules. . . . Account a = [SELECT . regardless of the class that initially called this inner class. ]. this call into CWith operates with enforced sharing rules // for the context user. the code execution returns to the sharing mode that was used to call this inner class. The sharing setting applies to all code contained in the class. . . Both inner classes and outer classes can be declared as with sharing. . 125 .Classes.m(). . CWith. the code execution // returns to without sharing mode. the current sharing rules remain in effect. } } public without sharing class CWithout { // All code in this class ignores sharing rules and operates // as if the context user has the Modify All Data permission. This means that if the class is called by a class that has sharing enforced. . When the call finishes. including initialization code. but inner classes do not inherit the sharing setting from their container class. . . // Again. To add an annotation to a method. In addition. similar to annotations in Java. Annotations are defined with an initial @ symbol. and Interfaces Annotations } } Warning: There is no guarantee that a class declared as with sharing doesn't call code that operates as without sharing. specify it immediately before the method or class definition. but which the current user does not have access to. regardless of the applied sharing rules. An operation may fail because the current user doesn't have the correct permissions. For example. all SOQL or SOSL queries that use PriceBook2 ignore the with sharing keyword. if the user specifies a foreign key value that exists in the organization. Enforcing the current user's sharing rules can impact: • • SOQL and SOSL queries. Objects. followed by the appropriate keyword. For example: global class MyClass { @future Public static void myMethod(String a) { //long-running Apex code } } Apex supports the following annotations: • • • • • • @Deprecated @Future @IsTest @ReadOnly @RemoteAction Apex REST annotations: ◊ ◊ ◊ ◊ ◊ ◊ @RestResource(urlMapping='/yourUrl') @HttpDelete @HttpGet @HttpPatch @HttpPost @HttpPut 126 . Class-level security is always still necessary.Classes. A query may return fewer rows than it would operating in system context. Annotations An Apex annotation modifies the way a method or class is used. DML operations. All PriceBook records are returned. Without the annotation. can still be referenced internally by the package developer. When you specify future. exceptions. interfaces. Use myOptimizedMethod(String a. you can use the future annotation when making an asynchronous Web service callout to an external service. @deprecated // This method is deprecated. and no additional processing can occur until the callout is complete (synchronous processing). For example: global class MyFutureClass { @future static void myMethod(String a.debug('Method called with: ' + a + ' and ' + i). such as a method or a class. global void myMethod(String a) { } Note the following rules when deprecating Apex identifiers: • • Unmanaged packages cannot contain code that uses the deprecated keyword. webService methods and variables cannot be deprecated. and can only return a void type. Methods with the future annotation must be static methods. while the elements continue to function for existing subscribers and API integrations. New subscribers cannot see the deprecated elements. Objects. Integer i) { System. or variables. Future Annotation Use the future annotation to identify methods that are executed asynchronously. the Web service callout is made from the same thread that is executing the Apex code. and Interfaces Deprecated Annotation Deprecated Annotation Use the deprecated annotation to identify methods. enums. other long running code } } 127 . String b) instead. all global access modifiers that reference the deprecated identifier must also be deprecated. exceptions. You cannot remove the deprecated annotation to undeprecate something in Apex after you have released a package version where that item in Apex is deprecated. The same syntax can be used to deprecate classes. must also be deprecated. • • • • • For more information about package versions. You can deprecate an enum but you cannot deprecate individual enum values. classes. define the method with the future annotation. To make a method in a class execute asynchronously.Classes. The following code snippet shows a deprecated method. For example. the method executes when Salesforce has available resources. You can deprecate an abstract class but you cannot deprecate individual abstract methods in an abstract class. //do callout. either in an input argument or the method return type. When an Apex item is deprecated. A deprecated item. Any global method that uses the deprecated type in its signature. interfaces. This is useful when you are refactoring code in managed packages as the requirements evolve. see Developing Apex in Managed Packages on page 220. You can deprecate an interface but you cannot deprecate individual methods in an interface. or variables that can no longer be referenced in subsequent releases of the managed package in which they reside. enums. called in a startTest. Chatter Only. Methods with the future annotation cannot take sObjects or objects as arguments. arrays of primitive data types. You cannot call a method annotated with future from a method that also has the future annotation. Objects. • Salesforce also imposes a limit on the number of future method invocations: 200 method calls per full Salesforce user license or Force. • • • Remember that any method using the future annotation requires special consideration because the method does not necessarily execute in the same order it is called. see Invoking Callouts Using Apex on page 240. Your entire organization is limited to only 1. all asynchronous processes are run synchronously. Individual test methods in a class not annotated with isTest do count against your organization code size limit. and 100 Customer Portal User licenses. or collections of primitive data types. per 24 hours. such as @future or executeBatch. Note: Classes defined with the isTest annotation don't count against your organization limit of 3 MB for all Apex code. nor in the constructor. The isTest annotation is similar to creating methods declared as testMethod. This is an organization-wide limit. Methods with the future annotation cannot be used in Visualforce controllers in either getMethodName or setMethodName methods. stopTest block. stopTest code block. Chatter customer users. not 200 x (3+2+100). Nor can you call a trigger from an annotated method that calls another annotated method.Classes. For more information about callouts. suppose your organization has three full Salesforce licenses. do not count against your limits for the number of queued jobs. and Interfaces IsTest Annotation The following snippet shows how to specify that a method executes a callout: @future (callout=true) public static void doCalloutFromFuture() { //Add code to perform callout } You can specify (callout=false) to prevent a method from making callouts. For example. call the class containing the method in a startTest. Methods with the future annotation have the following limits: • No more than 10 method calls per Apex invocation Note: Asynchronous calls. two Force. See Understanding Execution Governors and Limits on page 214. When stopTest is executed. The specified parameters must be primitive data types. calculated as 200 x (3+2). and partner portal User licenses aren’t included in this limit calculation. See Also: Understanding Execution Governors and Limits IsTest Annotation Use the isTest annotation to define classes or individual methods that only contain code used for testing your application.000 method calls every 24 hours. Customer Portal User. The getContent and getContentAsPDF PageReference methods cannot be used in methods with the future annotation. All asynchronous calls made after the startTest method are collected by the system.com App Subscription licenses.com App Subscription user license. 128 . To test methods defined with the future annotation. This is an example of a private test class that contains two test methods. However.com API version 23.0 or earlier continues to have access to all data in the organization and its data access is unchanged. Considerations of the IsTest(SeeAllData=true) Annotation • If a test class is defined with the isTest(SeeAllData=true) annotation.0.Classes. and Interfaces IsTest Annotation Starting with Apex code saved using Salesforce. this annotation applies to all its test methods whether the test methods are defined with the @isTest annotation or the testmethod keyword. see Running Unit Test Methods. that is. test code saved against Salesforce.0 or earlier continues to have access to all data in the organization and its data access is unchanged. test class methods can be invoked using the Salesforce user interface or the API.0 and later. including pre-existing data that the test didn’t create. use the isTest(SeeAllData=true) annotation to grant test classes and individual test methods access to all data in the organization. test methods don’t have access by default to pre-existing data in the organization.com API version 24. In addition. Classes defined as isTest must be top-level classes. However. See Isolation of Test Data from Organization Data in Unit Tests on page 149. test code saved against Salesforce.com API version 24. Methods of a public test class can only be called from a running test. a test method or code invoked by a test method. See Isolation of Test Data from Organization Data in Unit Tests on page 149. and can't be called by a non-test request.0.com API version 24. @isTest private class MyTestClass { // Methods for testing @isTest static void test1() { // Implement test code } @isTest static void test2() { // Implement test code } } This is an example of a public test class that contains utility methods for test data creation: @isTest public class TestUtil { public static void createTestAccounts() { // Create some test accounts } public static void createTestContacts() { // Create some test contacts } } Classes defined as isTest can't be interfaces or enums. test methods don’t have access by default to pre-existing data in the organization. For more information. Starting with Apex code saved using Salesforce.com API version 23. Classes and methods defined as isTest can be either private or public. 129 . IsTest(SeeAllData=true) Annotation For Apex code saved using Salesforce. Objects. Account testAccount2 = [SELECT Id. such as users.UserName). so it can access only the data it creates in addition to objects that are used to manage your organization.Email FROM User LIMIT 1]. @isTest private class ClassWithDifferentDataAccess { // Test method that has access to all data. // Create a test account based on the queried account. All the test methods in this class have access to all data in the organization. @isTest static void myTestMethod2() { // Can access all data in the organization. @isTest(SeeAllData=true) public class TestDataAccessClass { // This test accesses an existing account. } // Like the previous method. In this case. System. System. This example shows how to define a test class with the isTest(SeeAllData=true) annotation. you have to apply this annotation on the test method to enable access to all data for that test method. // This query returns the first user object. this test method can also access all data // because the containing class is annotated with @isTest(SeeAllData=true).debug('Email: ' + u.Email). Account testAccount = a. } // Test method that has access to only the data it creates // and organization setup and metadata objects. testAccount.assert(testAccount2 != null). However. @isTest static void testWithOwnDataAccess() { // This method can still access the User object. Account a = [SELECT Id. Because the class that the test method is contained in isn’t defined with this annotation. static testmethod void myTestMethod1() { // Query an existing account in the organization. the method will still have access to all the data in the organization. } } This second example shows how to apply the isTest(SeeAllData=true) annotation on a test method.Name = 'Acme Test'.debug('UserName: ' + u. Name FROM Account WHERE Name='Acme' LIMIT 1]. @isTest(SeeAllData=true) static void testWithAllDataAccess() { // Can query all data in the organization. 130 .clone(). insert testAccount. System.Classes. // It also creates and accesses a new test account. The second test method doesn’t have this annotation. and Interfaces IsTest Annotation • The isTest(SeeAllData=true) annotation is used to open up data access when applied at the class or method level. Name FROM Account WHERE Name='Acme Test' LIMIT 1]. System. // Query the test account that was inserted. // All test methods in this class can access all data. using isTest(SeeAllData=false) on a method doesn’t restrict organization data access for that method if the containing class has already been defined with the isTest(SeeAllData=true) annotation. User u = [SELECT UserName. Objects. // This class contains test methods with different data access levels.assert(a != null). @isTest(OnInstall=true) static void test1() { // Some test code } // Tests excluded from running during the // the installation of a package. public class OnInstallClass { // Implement logic for the class. won't be executed during installation. Account insertedAcct = [SELECT Id. if a Visualforce page calls 131 . Tests annotated to run during package installation must pass in order for the package installation to succeed. calls to methods annotated with @future.com database. the top level request must be in the schedule execution or the Web service invocation. test1 will be executed but test2 and test3 won't. It's important to note that this annotation. @isTest static void test2() { // Some test code } static testmethod void test3() { // Some test code } } ReadOnly Annotation The @ReadOnly annotation allows you to perform unrestricted queries against the Force. It is no longer possible to bypass a failing test during package installation. while removing the limit of the number of returned rows for a request.schedule. To use the @ReadOnly annotation. Objects. A test method or a class that doesn't have this annotation. will be executed during package installation. } } IsTest(OnInstall=true) Annotation Use the IsTest(OnInstall=true) annotation to specify which Apex tests are executed during package installation. System. Account a = new Account(Name='Test Account'). All other limits still apply. blocks you from performing the following operations within the request: DML operations. insert a. calls to System. or methods that are part of a test class that has this annotation. For example. and Interfaces ReadOnly Annotation // Can access the test account that is created here. // Access the account that was just created. In this example. Only test methods with this annotation. or that is annotated with isTest(OnInstall=false) or isTest. and sending emails. public void method1(){ // Some code } // This test method will be executed // during the installation of the package.Classes.Name FROM Account WHERE Name='Test Account'].assert(insertedAcct != null). This annotation is used for tests in managed or unmanaged packages. This example shows how to annotate a test method that will be executed during package installation. The @ReadOnly annotation is available for Web services and the Schedulable interface. Note: Methods with the RemoteAction annotation must be static and either global or public. or PageReference. your Apex method declaration is preceded with the @RemoteAction annotation like this: @RemoteAction global static String getItemId(String objectName) { . collections. user-defined Apex classes and enums... The default value is {escape: true}.method( [parameters. you can set the readonly attribute on the <apex:page> tag to true. see Working with Large Sets of Data in the Visualforce Developer's Guide. collections. and those methods will run with the same relaxed restrictions. callbackFunction receives the status of the method call and the result as parameters.. Generic sObjects must have an ID or sobjectType value to identify actual type. controller is the name of your Apex controller. UpsertResult.] callbackFunction. typed and generic sObjects. 132 .]controller. For more information. method is the name of the Apex method you’re calling.. the request fails because Visualforce is the top level request. such as the size of a collection that can be used by an iteration component like <apex:pageBlockTable>. Use this to specify whether or not to escape the Apex method’s response. or if • the class comes from an installed package. RemoteAction Annotation The RemoteAction annotation provides support for Apex methods used in Visualforce to be called via JavaScript. Objects. Apex REST Annotations Six new annotations have been added that enable you to expose an Apex class as a RESTful Web service. SaveResult. This process is often referred to as JavaScript remoting. add the request as a JavaScript invocation with the following form: [namespace. not the Web service. } Your method can take Apex primitives. see “JavaScript Remoting for Apex Controllers” in the Visualforce Developer's Guide.. You can also declare an anonymous function inline. parameters is the comma-separated list of parameters that your method takes. For more information. configuration configures the handling of the remote call and response. To increase other Visualforce-specific limits. and Interfaces RemoteAction Annotation a Web service that contains the @ReadOnly annotation. callbackFunction is the name of the JavaScript function that will handle the response from the controller. sObjects. • • • • • namespace is the namespace of the controller class. In your controller. Visualforce pages can call controller methods with the @ReadOnly annotation. [configuration] ). To use JavaScript remoting in a Visualforce page. Interface parameters must have an apexType to identify actual type.Classes. Your method can return Apex primitives. DeleteResult. SelectOption. and user-defined Apex classes and interfaces as arguments. This is required if your organization has a namespace defined. HttpDelete Annotation The @HttpDelete annotation is used at the method level and enables you to expose an Apex method as a REST resource. The URL mapping is case-sensitive.salesforce. Objects. if your class is in namespace abc and the class is mapped to your_url. URL Guidelines URL path mappings are as follows: • • The path must begin with a '/' If an '*' appears. This method is called when an HTTP DELETE request is sent. in which case it need not be followed by '/' The rules for mapping URLs are: • • • An exact match always wins. your Apex class must be defined as global. unless the '*' is the last character. the namespaced class is always used. In the case of a URL collision. 133 .com/services/apexrest/abc/your_url/. If no exact match is found. If no wildcard match is found.Classes. and deletes the specified resource. For example. The URL for a namespaced classes contains the namespace. then the API URL is modified as follows: https://instance. an HTTP response status code 404 is returned. your Apex method must be defined as global static. and then select the longest (by string length) of those. These are some considerations when using this annotation: • • • • The URL mapping is relative to https://instance. and Interfaces Apex REST Annotations • • • • • • @RestResource(urlMapping='/yourUrl') @HttpDelete @HttpGet @HttpPatch @HttpPost @HttpPut See Also: Apex REST Basic Code Sample RestResource Annotation The @RestResource annotation is used at the class level and enables you to expose an Apex class as a REST resource. To use this annotation. A URL mapping for my_url will only match a REST resource containing my_url and not My_Url. To use this annotation. find all the patterns with wildcards that match. A wildcard character (*) may be used.salesforce.com/services/apexrest/. it must be preceded by '/' and followed by '/'. Public virtual class Report { Public class CustomReport extends Report { // Create a list of report objects Report[] Reports = new Report[5]. This means that you can use casting to assign objects with the parent data type (Report) to the objects of the child data type (CustomReport). HttpPost Annotation The @HttpPost annotation is used at the method level and enables you to expose an Apex method as a REST resource. it is a child of that class. This means that Apex enables casting. that is. In the following example. and returns the specified resource. Therefore. This method is called when an HTTP PATCH request is sent. These are some considerations when using this annotation: • • To use this annotation. the custom report object is returned as a report object. your Apex method must be defined as global static. a data type of one class can be assigned to a data type of another class. all type information is available at runtime. Objects. After that. and creates or updates the specified resource. HttpPatch Annotation The @HttpPatch annotation is used at the method level and enables you to expose an Apex method as a REST resource. first. To use this annotation. This method is called when an HTTP GET request is sent. In the following code block. Use casting when you want to convert an object from one data type to another. then is cast back into a custom report object. To use this annotation. and Interfaces Classes and Casting HttpGet Annotation The @HttpGet annotation is used at the method level and enables you to expose an Apex method as a REST resource. but only if one class is a child of the other class. and updates the specified resource. HttpPut Annotation The @HttpPut annotation is used at the method level and enables you to expose an Apex method as a REST resource. your Apex method must be defined as global static. a custom report object is added to a list of report objects. Methods annotated with @HttpGet are also called if the HTTP request uses the HEAD request method. This method is called when an HTTP POST request is sent. // Because the custom report is a sub class of the Report class. CustomReport extends the class Report. and creates a new resource. 134 . Classes and Casting In general. your Apex method must be defined as global static. your Apex method must be defined as global static. // Create a custom report object CustomReport a = new CustomReport(). This method is called when an HTTP PUT request is sent. To use this annotation.Classes. add(a). use the instanceOf keyword. see Using the instanceof Keyword on page 121. because the compiler does not know that what you are returning is a custom report. get the first item in the list by casting it back to a custom report object CustomReport c = (CustomReport) Reports. Objects. // Instead. For more information. // // // // The following is not legal. Tip: To verify if a class is a specific type of class. } } Figure 4: Casting Example In addition.get(0). and Interfaces Classes and Casting // you can add the custom report object a to the list of report objects Reports.get(0). an interface type can be cast to a sub-interface or a class type that implements that interface. You must use cast to tell it that you know what type you are returning CustomReport c = Reports.Classes. 135 . that you can use a user-defined data type only for the value of a map. then MyC can be placed in the list. but do not require the static keyword. If the user of a PurchaseOrder list that only includes CustomerPurchaseOrders objects tries to insert a non-CustomerPurchaseOrder subclass of PurchaseOrder (such as InternalPurchaseOrder). but only because that instance was originally instantiated as a list of CustomerPurchaseOrder. Inner classes behave like static Java inner classes. Collection Casting Because collections in Apex have a declared type at runtime. POs = CPOs. This means. and Interfaces Classes and Collections Classes and Collections Lists and maps can be used with classes and interfaces. This is because Apex collections have a declared type at runtime. you cannot create a set of user-defined objects.} } Once the CustomerPurchaseOrder list is assigned to the PurchaseOrder list variable. For example. public virtual class PurchaseOrder { Public class CustomerPurchaseOrder extends PurchaseOrder { } { List<PurchaseOrder> POs = new PurchaseOrder[] {}. Inner classes can have instance member variables like outer classes. Static methods and variables can only be declared in a top-level class definition. List<CustomerPurchaseOrder> CPOs = new CustomerPurchaseOrder[]{}. even if the list of PurchaseOrder objects contains only CustomerPurchaseOrder objects. Apex allows collection casting. a runtime exception results. For instance. 136 . A list of PurchaseOrder objects that is instantiated as such cannot be cast to a list of CustomerPurchaseOrder objects. If you create a map or list of interfaces. and they have the same key type. but there is no implicit pointer to an instance of the outer class (using the this keyword). Note: Maps behave in the same way as lists with regards to the value side of the Map—if the value side of map A can be cast to the value side of map B. for example. any child type of the interface can be put into that collection. not in an inner class. Objects. A runtime error results if the casting is not valid with the particular map at runtime. Differences Between Apex Classes and Java Classes The following is a list of the major differences between Apex classes and Java classes: • • • Inner classes and interfaces can only be declared one level deep inside an outer class. in the same ways that lists and maps can be used with sObjects. a list of CustomerPurchaseOrder objects can be assigned to a list of PurchaseOrder objects if class CustomerPurchaseOrder is a child of class PurchaseOrder.Classes. not for the key. Collections can be cast in a similar manner that arrays can be cast in Java. it can be cast back to a list of CustomerPurchaseOrder objects. and MyC implements i1. then map A can be cast to map B. Likewise. if the List contains an interface i1. You can specify an older version of a managed package if you want to access components or functionality that differs from the most recent package version. not including comments. ◊ The override keyword must be used explicitly on methods that override base class methods. ◊ Exception classes have four implicit constructors that are built-in. A single class can be up to 1 million characters in length. classes are stored with an isValid flag that is set to true as long as dependent metadata has not changed since the class was last compiled. In the class editor. Class Definition Creation To create a class in Salesforce: 1. and means that the method or variable is accessible only within the Apex class in which it is defined. classes are stored with the version settings for a specified version of Apex and the API. or classes defined using @isTest. • • Interface methods have no modifiers—they are always global. not just the Apex code in the same application. 3. and Interfaces Class Definition Creation • • • • • The private access modifier is the default. ◊ The virtual definition modifier allows extension and overrides. If the Apex class references components. 5. Click New. you can also specify which version of each managed package to use with this class. the version settings for each managed package referenced by the class is saved too. Click Save to save your changes and return to the class detail screen. Methods and classes are final by default. as well as each managed package. If your organization has installed managed packages from the AppExchange. This access modifier should be used for any method that needs to be referenced outside of the application. 4. For more information. test methods. Click Your Name > Setup > Develop > Apex Classes. Additionally. or click Quick Save to save your changes and continue editing your class. such as a trigger. If you declare a method or variable as global. Classes can also be automatically generated from a WSDL by clicking Generate from WSDL. but only as local.Classes. although you can add others. ◊ Their names must end with the word exception. See SOAP Services: Defining a Class from a WSDL Document on page 241. Once saved. • Classes and interfaces can be defined in triggers and anonymous blocks. This associates the class with the most recent version of Apex and the API. classes can be invoked through class methods or variables by other Apex code. you must also declare the class that contains it as global. The global access modifier means the method or variable can be used by any Apex code that has access to the class. The public access modifier means the method or variable can be used by any Apex in this application or namespace. Use the default values for all versions. Note: To aid backwards-compatibility. 137 . see Exception Class on page 469. enter the Apex code for the class. either in the SOAP API or by other Apex code. 2. such as a custom object. in installed managed packages. Your Apex class must compile correctly before you can save your class. Objects. Click Version Settings to specify the version of Apex and the API used with this class. You can specify an older version of Apex and the API to maintain specific behavior. Specifying no access modifier for a method or variable and the private access modifier are synonymous. Exception classes must extend either exception or another user-defined exception. If you do not specify an access modifier. the method or variable is private. or trigger. the replace operation can also bind regular expression group variables ($1. When a trigger or Web service call invokes the class. • To use a regular expression as your search string. Search ( ) Search enables you to search for text within the current page. or if changes are made to a class that calls this class. enter the new string in the Replace textbox and click replace to replace just that instance. Objects. • To replace a found search string with another string. to replace an <h1> tag with an <h2> tag and keep all the attributes on the original <h1> intact. This can be used with go to line ( ) to quickly navigate through the editor. For example.Classes. The Apex Class Editor When editing Visualforce or Apex. the isValid flag is set to false. either in the Visualforce development mode footer or from Setup.*)> and replace it with <h2$1$2>. Line and column position The line and column position of the cursor is displayed in the status bar at the bottom of the editor. select the Match Case option. 138 . If you use the replace operation with a string found by a regular expression. including superficial changes such as edits to an object or field description. or trigger. A search using regular expressions can find strings that wrap over more than one line. or Replace All to replace that instance and all other instances of the search string that occur in the page. The regular expressions follow JavaScript's regular expression rules. class. select the Regular Expressions option. Font size Select a font size from the drop-down list to control the size of the characters displayed in the editor. To use search. the isValid flag is reset to true. $2. Undo ( ) and Redo ( ) Use undo to reverse an editing action and redo to recreate an editing action that was undone. If there are no errors. the editor scrolls to that line. Go to line ( ) This button allows you to highlight a specified line number. the code is recompiled and the user is notified if there are any errors. class. an editor is available with the following functionality: Syntax highlighting The editor automatically applies syntax highlighting for keywords and all functions and operators. and so on) from the found search string. and Interfaces Class Definition Creation If any changes are made to object names or fields that are used in the class. enter a string in the Search textbox and click Find Next. Line and character count The total number of lines and characters is displayed in the status bar at the bottom of the editor. • To make the search operation case sensitive. search for <h1(\s+)(. If the line is not currently visible. Shadow(String s) { this. and a class within a class to have the same name. Next to the name of the class that you want to restrict.s = s.c c = new p1. For example. In particular it is legal for a variable. To set Apex class security from the class list page: 1. Name Shadowing Member variables can be shadowed by local variables—in particular function arguments.CLASS_INT. Objects. and Interfaces Naming Conventions Naming Conventions We recommend following Java standards for naming. a subclass C can also declare a static S. Static variables can be shadowed across the class hierarchy—so if P defines a static S.CLASS_INT. For example: public class p1 { public static final Integer CLASS_INT = 1. Static class variables cannot be referenced through a class instance. methods start with a lowercase verb. public class c { }. However. and variable names should be meaningful.S must be used. click Security. not on triggers. methods and variables have their own namespaces within the class so these three types of names do not clash with each other. Click Your Name > Setup > Develop > Apex Classes. References to S inside C refer to that static—in order to reference the one in P.s = s. It is also not legal for an inner class to have the same name as its outer class. } p1. if one has a reference to a class C and wants to gain access to a member variable M in parent class P (with the same name as a member variable in C) the reference should be assigned to a reference to P first. that is.c(). // This is correct Integer i = p1. classes start with a capital letter. method.Classes. 139 . Class Security You can specify which users can execute methods in a particular top-level class based on their user profile or permission sets. 2. // This is illegal // Integer i = c. They must be referenced using the raw variable name by itself (inside that top-level class file) or prefixed with the class name. the syntax P. This can be useful if the two classes are in different top-level classes and written by different teams. It is not legal to define a class and interface with the same name in the same class. You can only set security on Apex classes. } // Same name ok setS(String s) { this. This allows methods and constructors of the standard Java form: Public Class Shadow { String s. } // Same name ok } Member variables in one class can shadow member variables with the same name in a parent classes. To set Apex class security from a permission set: 1. Select the profiles that you want to enable from the Available Profiles list and click Add. click Edit. 2. 4. field-level security. Click Your Name > Setup > Manage Users > Profiles. For example. 6.DescribeFieldResult exposes these access control methods that you can call to check 140 . 3. Select the Apex classes that you want to enable from the Available Apex Classes list and click Add. that is. executeAnonymous always executes using the full permissions of the current user. or select the Apex classes that you want to disable from the Enabled Apex Classes list and click Remove. 5. Click Save. Similarly.DescribeSObjectResult to verify whether the current user has read. you can then perform a specific DML operation or a query. see Anonymous Blocks on page 98. or select the Apex classes that you want to disable from the Enabled Apex Classes list and click Remove. 2. Click Save.DescribeFieldResult) that check the current user's access permission levels. To set Apex class security from a profile: 1. Click Apex Class Access. 3. To set Apex class security from the class detail page: 1. The only exceptions to this rule are Apex code that is executed with the executeAnonymous call. Select the Apex classes that you want to enable from the Available Apex Classes list and click Add. 4. you can call the isAccessible. In the Apex Class Access page or related list. or select the profiles that you want to disable from the Enabled Profiles list and click Remove. For more information on executeAnonymous. 5. or select the profiles that you want to disable from the Enabled Profiles list and click Remove. Click Your Name > Setup > Develop > Apex Classes. Select the profiles that you want to enable from the Available Profiles list and click Add. and Interfaces Enforcing Object and Field Permissions 3. Schema. Although Apex doesn't enforce object-level and field-level permissions by default. 2. isCreateable. 4. 5. Enforcing Object and Field Permissions Apex generally runs in system context. and sharing rules aren’t taken into account during code execution. Click Edit. Select a profile.Classes. In this way. create. or isUpdateable methods of Schema. the current user's permissions. Click the name of the class that you want to restrict. Click Your Name > Setup > Manage Users > Permission Sets. respectively. Click Security. you can verify if the current user has the necessary permissions. and only if he or she has sufficient permissions.DescribeSObjectResult) and the field describe result methods (of Schema. Objects. Select a permission set. you can enforce these permissions in your code by explicitly calling the sObject describe result methods (of Schema. 4. Click Save. 3. or update access to an sObject. Click Save. fields.Classes.Contact. 141 . Consequently. if (Schema. If sharing rules are defined in Salesforce. These are some examples of how to call the access control methods.sObjectType. For more information. and Interfaces Namespace Prefix the current user's read.isCreateable()) { // Create new contact } To check the field-level read permission of the contact's email field before querying for this field: if (Schema. or update access for a field.DescribeSObjectResult to check if the current user has permission to delete a specific sObject. When looking at identifiers.Contact. } To check the object-level permission for the contact before deleting the contact. SOSL statements.Contact.Email.sObjectType. external references to custom object and field names in the developer's managed packages take on the following long format: namespace_prefix__obj_or_field_name__c Because these fully-qualified names can be onerous to update in working SOQL statements. After a developer registers a globally unique namespace prefix and registers it with AppExchange registry. To check the field-level update permission of the contact's email field before updating it: if (Schema.” Apex supports a default namespace for schema names. the parser considers the namespace of the current object and then assumes that it is the namespace of all other objects and fields unless otherwise specified.com AppExchange packages to differentiate custom object and field names from those in use by other organizations.Contact.fields. the verification of object and field-level permissions is performed in addition to the sharing rules that are in effect. you can enforce them at the class level by declaring the class with the with sharing keyword. Namespace prefixes are used in managed Force. the access level granted by a sharing rule could conflict with an object-level or field-level permission.sObjectType. a stored class should refer to custom object and field names directly (using obj_or_field_name__c) for those objects that are defined within its same application namespace. If you call the sObject describe result and field describe result access control methods.Email.sObjectType.isAccessible()) { Contact c = [SELECT Email FROM Contact WHERE Id= :Id]. They can coexist. and Apex once a class is marked as “managed.isDeletable()) { // Delete contact } Sharing rules are distinct from object-level and field-level permissions.Email. create. see Using the with sharing or without sharing Keywords. you can call the isDeletable method provided by Schema. Namespace Prefix The application supports the use of namespace prefixes. Sometimes. In addition.fields.isUpdateable()) { // Update contact phone number } To check the field-level create permission of the contact's email field before creating a new contact: if (Schema. Objects. nameN()).nameN are field references. and Variable Name Precedence Because local variables. name2 is a static variable name with name3 . 4. If the first assumption does not hold true. If the expression contains more than two identifiers. Tip: Only use namespace prefixes when invoking methods in managed packages that have been installed to your organization from theAppExchange. the parser then assumes that name1 is a namespace name. System. name3 is a static variable name. The parser first assumes that name1 is a local variable with name2 .nameM are field references..nameN as field references. and nameN as a method invocation.nameN as field references. or they might refer to an sObject which has its own dot notation rules to refer to field names (possibly navigating foreign keys). the Apex parser evaluates expressions in the form of name1.[. 2. 142 .. However. Objects. with class variables Apex also uses dot notation to reference member variables. name4 . the parser then assumes that name1 is a namespace name.. the parser reports an error. and namespaces can all hypothetically use the same identifiers. Apex allows fully-qualified identifiers of the form: namespace_prefix. If the expression ends with a set of parentheses (for example. name2 is a class name. 2. 3.name2. and Interfaces Using Namespaces When Invoking Methods Tip: Only use namespace prefixes when referring to custom objects and fields in managed packages that have been installed to your organization from theAppExchange.nameM as field references.method(args) Use the special namespace System to disambiguate the built-in static classes from any user-defined ones (for example. class names. The parser first assumes that name1 is a local variable with name2 . If the third assumption does not hold true.Classes. the Apex parser evaluates the expression as follows: 1. Without the System namespace prefix.].name2. the parser then assumes that name1 is a class name. 3.]. Those member variables might refer to other class instances.name2()). If the third assumption does not hold true. as outlined below.class. system static class names such as Math and System can be overridden by user-defined classes with the same name.[. 4.debug()). If the first assumption does not hold true: • • If the expression contains only two identifiers (name1. name2 is a class name. If the second assumption does not hold true. name3 is a static variable name.nameN as follows: 1. If the second assumption does not hold true.System..nameM.nameM as field references. name1. the parser then assumes that name1 is a class name and name2 is a static variable name with name3 . the parser reports an error. and name4 . and nameN is a method invocation. Namespace. the parser then assumes that name1 is a class name and name2 is a method invocation. and nameN is a method invocation. Using Namespaces When Invoking Methods To invoke a method that is defined in a managed package. Class. known behavior. the API.Classes.c1. the remainder of the expression stays within the sObject domain. Typically. in installed managed packages. For the type T1.com API version and each installed package version.c2. the class or trigger is associated with the latest installed version of the managed package by default. If TypeN still is not found. such as a custom object. you reference the latest Salesforce. Objects.owner. 3. } class c2 { Account a. if you have the following class: public class c { c1 c1 = new c1().a.contacts. This allows you to continue to reference Apex that may be deprecated in the latest version of an installed package. 4. If TypeN still is not found.name c. For instance. classes and triggers are stored with the version settings for a specific Salesforce.c1.c1. If TypeN is not found.toLowerCase() c.a. 2. the class or trigger is associated with the latest installed version by default. Setting a version for an installed package determines the exposed interface and behavior of any Apex code in the installed package. This ensures that as Apex. if you installed a version of the package before the code was deprecated. sObject fields cannot refer back to Apex expressions. If an Apex class or trigger references components. 143 . For a type reference TypeN. a class or trigger is still bound to versions with specific.a.c1.com API version. Version Settings To aid backwards-compatibility. If you save an Apex class or trigger without specifying the Salesforce.c2. the parser first looks up that type as a scalar type. class c1 { c2 c2. If you save an Apex class or trigger that references a managed package without specifying a version of the managed package.c2.a.T2 this could mean an inner type T2 in a top-level class T1. the Apex parser evaluates types as follows: 1. or it could mean a top-level class T2 in the namespace T1 (in that order of precedence).tasks c.c2. } } Then the following expressions are all legal: c.com API version. that is. the parser looks up locally defined types. the parser looks up a class of that name. and Interfaces Type Resolution and System Namespace for Types Once you enter an sObject field in the expression.lastName.size() Type Resolution and System Namespace for Types Because the type system must resolve user-defined types defined locally or in other classes. and the components in managed packages evolve in subsequent released versions. the version settings for each managed package referenced by the class are saved too. the parser looks up system types such as sObjects. 0 by Version Settings private class C1 { static testMethod void testC2Method() { Idea i = new Idea().insertIdea(i). i. // assert that the categories field from the object created // in this class is not null System. because the Categories field is not available in version 13. C1.0'.CommunityId = '09aD000000004YCIAY'. // assert that the categories field created in C2 is null System. to another class.assert(ideaMoreFields.com API version setting. i.0: // This class is saved using Salesforce API version 13. // category field set to null on insert // retrieve the new idea Idea insertedIdea = [SELECT title FROM Idea WHERE Id =:a.com API and Apex version for a class or trigger: 1. } } The following class is saved using Salesforce. the fields in the objects are controlled by the version settings of C2. the Categories field is set to null after calling the insertIdea method in class C2 from a method in the test class C1.Categories = 'test'. C2 c2 = new C2(). 2.categories field global class C2 { global Idea insertIdea(Idea a) { insert a.Id]. This is also the version of Apex associated with the class or trigger.Title = 'Testing Version Settings'.Id]. and C2 has different fields exposed due to the Salesforce.Classes. C2. The first class is saved using Salesforce.com API version 16.0 does not include the Idea.assert(i. Edit either a class or trigger. Select the Version of the Salesforce.0 of the API. Idea returnedIdea = c2.0 // Version 13. and click Version Settings. and Interfaces Setting the Salesforce API Version for Classes and Triggers Setting the Salesforce API Version for Classes and Triggers To set the Salesforce. // retrieve the new idea Idea ideaMoreFields = [SELECT title.Categories != null). If you pass an object as a parameter in a method call from one Apex class. Using the following example.0: @isTest // This class is bound to API version 16. } } 144 .Body = 'Categories field is included in API version 16. Click Save.Categories == null). Objects.com API version 13.com API. categories FROM Idea WHERE Id = :returnedIdea. 3. return insertedIdea. i. i. The list is only displayed if you have an installed managed package that is not already associated with the class or trigger. Note the following when working with package version settings: • • If you save an Apex class or trigger that references a managed package without specifying a version of the managed package. Objects. 3. 145 . select a package from the list of available packages.Classes. Use Show Dependencies to find where a managed package is referenced by a class or trigger. Click Save. To add an installed managed package to the settings list. 2. and click Version Settings. unless you manually update the version setting. You cannot Remove a class or trigger's version setting for a managed package if the package is referenced in the class or trigger. Select a Version for each managed package referenced by the class or trigger. the Apex class or trigger is associated with the latest installed version of the managed package by default. Edit either a class or trigger. This version of the managed package will continue to be used by the class or trigger if later versions of the managed package are installed. and Interfaces Setting Package Versions for Apex Classes and Triggers Setting Package Versions for Apex Classes and Triggers To configure the package version settings for a class or trigger: 1. run your tests. and have code coverage results. check test results. This chapter provides an overview of unit tests..Chapter 5 Testing Apex In this chapter . • • • • • Understanding Testing in Apex Unit Testing Apex Running Unit Test Methods Testing Best Practices Testing Example 146 ..com platform for testing Apex. data visibility for tests. as well as the tools that are available on the Force. • • • • • Understanding Testing in Apex Unit Testing Apex Running Unit Test Methods Testing Best Practices Testing Example Apex provides a testing framework that allows you to write unit tests. All classes and triggers must compile successfully. • At least 75% of your Apex code must be covered by unit tests.Testing Apex Understanding Testing in Apex Understanding Testing in Apex Testing is the key to successful long term development. where you change and extend functionality. may be invoked for 1 to 200 records. expected result. that is. 147 . that there are no unexpected behaviors. and is a critical component of the development process. Why Test Apex? Testing is key to the success of your application. Note the following.debug are not counted as part of Apex code coverage. particularly if your application is to be deployed to customers. you should make sure that every use case of your application is covered. whether a trigger. Calls to System. • • Every trigger must have some test coverage. Before you can deploy your code or package it for the Force. While only 75% of your Apex code must be covered by tests.com AppExchange. Test methods and test classes are not counted as part of Apex code coverage. but the bulk cases as well. the following must be true. that is. Instead. You must test not only the single record case. as well as bulk and single record. An application is seldom finished. including positive and negative cases. What to Test in Apex Salesforce. Positive behavior Test to verify that the expected behavior occurs through every expected permutation. We strongly recommend that you use a test-driven development process. you can ensure that a regression is not introduced with any new functionality. You will have additional releases of it. The other way is to test for bulk functionality: up to 200 records can be passed through your code if it's invoked using SOAP API or by a Visualforce standard set controller. but merely testing through the user interface will not catch all of the use cases for your application. ◊ ◊ ◊ ◊ When deploying to a production organization. If you have written comprehensive tests. every unit test in your organization namespace is executed. a class or an extension. Salesforce runs all tests in all organizations that have Apex code to verify that no behavior has been altered as a result of any service upgrades. There are two ways of testing an application. your focus shouldn't be on the percentage of code that is covered. test development that occurs at the same time as code development. This should lead to 75% or more of your code being covered by unit tests.com recommends that you write tests for the following: Single action Test to verify that a single record produces the correct. Bulk actions Any Apex code. important. One is through the Salesforce user interface. your customers are going to trust you more. If you validate that your application works as expected. and all of those tests must complete successfully. that the user filled out everything correctly and did not go past the limits. For example: public class myClass { static testMethod void myTest() { code_block } } Use the isTest annotation to define classes or individual methods that only contain code used for testing your application. within the limits cases. Restricted user Test whether a user with restricted access to the sObjects used in your code sees the expected behavior. error-free code. not being able to specify a negative amount. Unit tests are class methods that verify whether a particular piece of code is working properly. You must test for the negative case and verify that the error messages are correctly produced as well as for the positive. send no emails. Unit Testing Apex To facilitate the development of robust. The isTest annotation is similar to creating methods declared as testMethod. commit no data to the database.Testing Apex Unit Testing Apex Negative behavior There are likely limits to your applications. and so on. Note: Conditional and ternary operators are not considered executed unless both the positive and negative branches are executed. Unit test methods take no arguments. Individual test methods in a class not annotated with isTest do count against your organization code size limit. such as not being able to add a future date. @isTest private class MyTestClass { // Methods for testing @isTest static void test1() { // Implement test code } @isTest static void test2() { // Implement test code } } 148 . See Understanding Execution Governors and Limits on page 214. whether they can run the code or receive error messages. That is. see Testing Example on page 157. Apex supports the creation and execution of unit tests. and are flagged with the testMethod keyword in the method definition. Note: Classes defined with the isTest annotation don't count against your organization limit of 3 MB for all Apex code. For examples of these types of tests. This is an example of a test class that contains two test methods. use mock callouts. such as standard objects. they don't result in the creation of FeedTrackedChange records. test methods don’t have access by default to pre-existing data in the organization. and custom settings data. For more information.0 and later. even though it was saved in an earlier version.com API version 23. the data access restrictions of the caller are enforced in the called method. you don’t have to delete test data upon completion. FeedTrackedChange records require the change to the parent record they're associated with to be committed to the database before they're created. For example. For some sObjects that have fields with unique constraints.0 or earlier continues to have access to all data in the organization and its data access is unchanged. • • • • Test methods can’t be used to test Web service callouts. Instead.com API version 24. You can’t send email messages from a test method. See Testing Web Service Callouts and Testing HTTP Callouts. that is. Test code saved using Salesforce. inserting duplicate sObject records results in an error. you should create test data for each test. objects that are used to manage your organization or metadata objects can still be accessed in your tests such as: • • • • • • • • User Profile Organization RecordType ApexClass ApexTrigger ApexComponent ApexPage Whenever possible. Since test methods don’t commit data created in the test. However. inserting CollaborationGroup sObjects with the same name results in an error because CollaborationGroup records must have unique names. field history tracking records (such as AccountHistory) can't be created in test methods because they require other sObject records to be committed first (for example. • See Also: IsTest Annotation Isolation of Test Data from Organization Data in Unit Tests Starting with Apex code saved using Salesforce. You can disable this restriction by annotating your test class or test method with the IsTest(SeeAllData=true) annotation. Similarly. Data Access Considerations • If a new test method saved using Salesforce. Account). Tracked changes for a record (FeedTrackedChange records) in Chatter feeds aren't available when test methods modify the associated record.com API version 24.0 or later calls a method in another class saved using version 23.Testing Apex Isolation of Test Data from Organization Data in Unit Tests Unit Test Considerations Here are some things to note about unit tests. and can only access data that they create. custom objects. Since test methods don't commit data. 149 . the called method won’t have access to organization data because the caller doesn’t. see IsTest(SeeAllData=true) Annotation.0 or earlier. ◊ Records that are created only after related records are committed to the database. and the permissions and record sharing of the current user are not taken into account. field history tracking records (such as AccountHistory) can't be created in test methods because they require other sObject records to be committed first (for example. the executing test stays in test context but runs in a different thread. if the Visualforce request performs a callback. This happens whether or not your test is annotated with IsTest(SeeAllData=true). In the following example. LanguageLocaleKey='en_US'. When running as a user. For example. 150 . they don't result in the creation of FeedTrackedChange records. If a test makes a Visualforce request. with that user's permissions and record access: public class TestRunAs { public static testMethod void testRunAs() { // Setup test data // This code runs as the system user Profile p = [SELECT Id FROM Profile WHERE Name='Standard User']. the test will be able to access all data in the organization after initiating the Visualforce request. ◊ For some sObjects that have fields with unique constraints. any data inserted by the callback won't be visible to the test. Tracked changes for a record (FeedTrackedChange records) in Chatter feeds aren't available when test methods modify the associated record. a new test user is created. Also. The system method runAs enables you to write test methods that change either the user contexts to an existing user or a new user. like tracked changes in Chatter. User u = new User(Alias = 'standt'. or to run using the code from a specific version of a managed package. The original system context is started again after all runAs test methods complete. inserting a pricebook entry for a custom pricebook isn’t supported since this requires defining a standard pricebook. see the Object Reference for Salesforce and Force. However. inserting duplicate sObject records results in an error.com'. all of that user's record sharing is then enforced. such as a JavaScript remoting call. all Apex code runs in system mode. LastName='Testing'. Note: Every call to runAs counts against the total number of DML statements issued in the process. Email='standarduser@testorg. inserting CollaborationGroup sObjects with the same name results in an error because CollaborationGroup records must have unique names. For example. There might be some cases where you can’t create certain types of data from your test method because of specific limitations. then code is run as that user. Since test methods don't commit data. FeedTrackedChange records require the change to the parent record they're associated with to be committed to the database before they're created. see Testing Behavior in Package Versions on page 224. Using the runAs Method Generally. ◊ Inserting a pricebook entry for a product isn’t feasible from a test since the standard pricebook isn’t accessible and can’t be created in a running test. For such situations. the trigger won’t be able to either. For information on using the runAs method and specifying a package version context.com. For more information on these objects. ◊ Some standard objects aren’t createable. Account). if a test method causes a trigger to execute and the test can’t access organization data.Testing Apex Using the runAs Method • • • This access restriction to test data applies to all code running in test context. so test data isolation is no longer enforced. Similarly. EmailEncodingKey='UTF-8'. Here are some examples of such limitations. In this case. You can only use runAs in a test method. annotate your test method with IsTest(SeeAllData=true) so that your test can access organization data. UserName='standarduser@testorg. System.getProfileId()). while the second version contains the word “limit” and returns the total amount of the resource that is available for that context.runAs(u2) { // The following code runs as user u2.getProfileId()).getUserName()).com'].debug('Current User: ' + UserInfo.getUserName()). LanguageLocaleKey='en_US'. UserName='
[email protected]('Current User: ' + UserInfo. and stopTest The Limits methods return the specific limit for the particular governor.com'.getProfileId()). System. such as the number of calls of a method or the amount of heap size remaining. There are two versions of every method: the first returns the amount of the resource that has been used in the current context. System. User u3 = [SELECT Id FROM User WHERE UserName='newuser@testorg. } } } You can nest more than one runAs method. Email='newuser@testorg. TimeZoneSidKey='America/Los_Angeles'. System. and stopTest LocaleSidKey='en_US'. 151 . } // Any additional code here would run as user u2. startTest.Id.getUserName()). LastName='Testing'. ProfileId = p. LocaleSidKey='en_US'.debug('Current User: ' + UserInfo. EmailEncodingKey='UTF-8'. System.com'). Using Limits. The runAs method ignores user license limits. // The following code runs as user u3. ProfileId = p.Id. System. } } } Best Practices for Using runAs The following items use the permissions granted by the user specified with runAs running as a specific user: • • • Dynamic Apex Methods using with sharing or without sharing Shared records The original permissions are reset after runAs completes.runAs(u3) { System.Testing Apex Using Limits. System.debug('Current Profile: ' + UserInfo.com'). You can create new users with runAs even if your organization has no additional user licenses. User u2 = new User(Alias = 'newUser'. TimeZoneSidKey='America/Los_Angeles'. For example: public class TestRunAs2 { public static testMethod void test2() { Profile p = [SELECT Id FROM Profile WHERE Name='Standard User']. startTest.debug('Current Profile: ' + UserInfo.runAs(u) { // The following code runs as user 'u' System.debug('Current Profile: ' + UserInfo. Each testMethod is allowed to call this method only once. populate data structures. All SOSL queries that take place later in the test method return the list of record IDs that were specified by the Test. 152 . the test method can call Test. The startTest method does not refresh the context of the test: it adds a context to your test. all asynchronous processes are run synchronously. For example. however. } } Although the account record with an ID of 001x0000003G89h may not match the query string in the FIND clause ('test').setFixedSearchResults(fixedSearchResults). All of the code before this method should be used to initialize variables. while getLimitCallouts returns the total number of callouts available in the given context. they are applied to the list of fixed search results. Each testMethod is allowed to call this method only once. no record is returned. if your class makes 98 SOQL queries before it calls startTest. or if you call this method without specifying a list of record IDs. the record is passed into the RETURNING clause of the SOSL statement. When stopTest is executed. Adding SOSL Queries to Unit Tests To ensure that test methods always behave in a predictable way. any Salesforce Object Search Language (SOSL) query that is added to an Apex test method returns an empty set of search results when the test method executes.Testing Apex Adding SOSL Queries to Unit Tests For example. In addition to the Limits methods.setFixedSearchResults method. If the record with ID 001x0000003G89h matches the WHERE clause filter. getCallouts returns the number of callouts to an external service that have already been processed in the current context. If you do not want the query to return an empty list of results. Test.setFixedSearchResults system method to define a list of record IDs that are returned by the search. you can use the Test. use the startTest and stopTest methods to validate how close the code is to reaching governor limits. Use this method in conjunction with the startTest method. For example: public class SoslFixedResultsTest1 { public static testMethod void testSoslFixedResults() { Id [] fixedSearchResults= new Id[1]. The list of record IDs specified by the Test. Additionally. and the first significant statement after startTest is a DML statement. The stopTest method marks the point in your test code when your test ends. The startTest method marks the point in your test code when your test actually begins. List<List<SObject>> searchList = [FIND 'test' IN ALL FIELDS RETURNING Account(id. If you do not call the Test. name WHERE name = 'test' LIMIT 1)]. the program can now make an additional 100 queries. any SOSL queries that take place later in the test method return an empty list of results. Any code that executes after the call to startTest and before stopTest is assigned a new set of governor limits. and can only make 2 additional SOQL queries before reaching the limit of 100. Once stopTest is called.setFixedSearchResults method replaces the results that would normally be returned by the SOSL query if it were not subject to any WHERE or LIMIT clauses. the program goes back into the original context.setFixedSearchResults method in a test method. allowing you to set up everything you need to run your test. All asynchronous calls made after the startTest method are collected by the system. and so on. Any code that executes after the stopTest method is assigned the original limits that were in effect before startTest was called. If it does not match the WHERE clause. the record is returned.setFixedSearchResults multiple times to define different result sets for different SOSL queries. fixedSearchResults[0] = '001x0000003G89h'. If these clauses exist in the SOSL query. 2.. you must compile these classes first by clicking Compile all classes on the Apex Classes page so that they appear in the list. select [My Namespace] from the drop-down list. use any of the following: • • • The Salesforce user interface The Force. Only the classes of the managed package with the selected namespace appear in the list. The Apex Test Execution page refreshes the status of a test and displays the results after the test completes. The list of tests contains classes that contain test methods. Click Your Name > Setup > Develop > Apex Test Execution. • • • To select tests from an installed managed package. whether or not they are from a managed package.com IDE The API Running Tests Through the Salesforce User Interface You can run unit tests on the Apex Test Execution page. Only local classes that aren't from managed packages appear in the list.Testing Apex Running Unit Test Methods Running Unit Test Methods You can run unit tests for: • • • A specific class A subset of classes All unit tests in your organization To run a test. you don't have to wait for a test class execution to finish. Tests started on this page run asynchronously.. Note: If you have Apex classes that are installed from a managed package. Click Select Tests. See “Managing Apex Classes” in the online help. 153 . select its corresponding namespace from the drop-down list. To use the Apex Test Execution page: 1. All the classes in the organization appear.. that is. select [All Namespaces] from the drop-down list. 3. To select any test. Select the tests to run. To select tests that exist locally in your organization. that you can insert in the Apex job queue is the greater of 500 or 10 multiplied by the number of test classes in the organization. If you insert multiple Apex test queue items in a single bulk operation. Note: The code coverage value computed by Estimate your organization's code coverage might differ from the code coverage value computed after running all unit tests using Run All Tests. then click the percentage number in the Code Coverage column for a class. It then returns the parent job ID of one queue item. and pass 154 . the queue items will share the same parent job. use these objects: • • ApexTestQueueItem: Represents a single Apex class in the Apex job queue. you can display the percentage of code covered by those tests on the list of Apex classes. not just tests that you have run. After the job executes.Testing Apex Running Unit Test Methods Note: Classes whose tests are still running don't appear in the list. ApexTestResult contains the result for each single test method executed as part of the test. Test results are retained for 30 days after they finish running. unless cleared.com/index. To abort a class that is in the Apex job queue. The maximum number of test queue items.developerforce. then click Estimate your organization's code coverage. This example shows how to use DML operations to insert and query the ApexTestQueueItem and ApexTestResult objects. Running Tests Using the Force. Click Your Name > Setup > Develop > Apex Test Execution > View Test History to view all test results for your organization. You can also verify which lines of code are covered by tests for an individual class. Running Tests Using the API Note: The API for asynchronous test runs is a Beta release.com IDE (see https://wiki. This means that a test run can consist of the execution of the tests of several classes if all the test queue items are inserted in the same bulk operation. ApexTestResult: Represents the result of an Apex test method execution. After you run tests using the Apex Test Execution page.php/Apex_Toolkit_for_Eclipse). Click Your Name > Setup > Develop > Apex Classes. The Apex job executes the test methods in the class. you can execute tests with the Force. To start an asynchronous execution of unit tests and check their results. The checkClassStatus method retrieves all the queue items that correspond to the specified job ID. perform an update operation on the ApexTestQueueItem object and set its Status field to Aborted. which is the same for all queue items because they were inserted in bulk. job status. Click Your Name > Setup > Develop > Apex Classes. It then queries and outputs the name. This enables you to not only start tests asynchronously but also schedule your tests to execute at specific times by using the Apex scheduler. and hence classes.com IDE In addition. This is because Estimate your organization's code coverage excludes classes that are part of installed managed packages while Run All Tests doesn't. Click Run. you can add tests to the Apex job queue for execution and check the results of completed test runs. 4. See Apex Scheduler for more information. Using objects and Apex code to insert and query those objects. Insert an ApexTestQueueItem object to place its corresponding Apex class in the Apex job queue for execution. The enqueueTests method inserts queue items for all classes that end with Test. public static void checkMethodStatus(ID jobId) { ApexTestResult[] results = [SELECT Outcome. Message.ApexClass. public class TestUtil { // Enqueue all classes ending in "Test". if (testClasses.debug(item. The checkMethodStatus method gets information of each test method that was executed as part of the job.size() > 0) { ApexTestQueueItem[] queueItems = new List<ApexTestQueueItem>().Name. if (atr. } insert queueItems.StackTrace).Message + '\n at ' + atr.Status + extStatus). ExtendedStatus FROM ApexTestQueueItem WHERE ParentJobId=:jobId]. } } } } You can also use the runTests() call from the SOAP API to run tests synchronously: RunTestsResult[] runTests(RunTestsRequest ri) This call allows you to run all tests in all classes.extendedstatus == null ? '' : item. } } // Get the result for each test method that was executed. for (ApexTestResult atr : results) { System. public static ID enqueueTests() { ApexClass[] testClasses = [SELECT Id FROM ApexClass WHERE Name LIKE '%Test'].MethodName + ': ' + atr.Testing Apex Running Unit Test Methods rate for each class.debug(atr. for (ApexClass cls : testClasses) { queueItems.Outcome). ApexTestQueueItem item = [SELECT ParentJobId FROM ApexTestQueueItem WHERE Id=:queueItems[0]. for (ApexTestQueueItem item : items) { String extStatus = item. // Get the job ID of the first queue item returned. public static void checkClassStatus(ID jobId) { ApexTestQueueItem[] items = [SELECT ApexClass.Name + '.parentjobid. StackTrace FROM ApexTestResult WHERE AsyncApexJobId=:jobId].Id)). MethodName. as specified in the RunTestsRequest object. return item. Status.Name + ': ' + item. } return null.extendedStatus. ApexClass.debug(atr. It returns the following: • Total number of tests that ran 155 . or all tests in a subset of classes in a specific namespace. all tests in a specific namespace.Id LIMIT 1]. } // Get the status and pass rate for each class // whose tests were run by the job.ApexClass.' + atr. // that correspond to the specified job ID. System.Name.message != null) { System.add(new ApexTestQueueItem(ApexClassId=cls. See IsTest Annotation on page 128. 156 . Make calls to methods using both valid and invalid inputs. When deploying to a production organization.Testing Apex Testing Best Practices • • • • Code coverage statistics (described below) Error information for each failed test Information for each test that succeeds Time it took to run the test For more information on runTests(). such as adding a unique constraint to an existing field.assert methods to prove that code behaves properly.salesforce. where your_salesforce_server is equivalent to the server on which your organization is located. it is still important to use runTests() to verify that the existing unit tests run to completion after a change is made. including positive and negative cases. While only 75% of your Apex code must be covered by tests. For more information. Use System. as well as bulk and single record. Test methods and test classes are not counted as part of Apex code coverage. see Deploying Apex on page 594. Important: ◊ At least 75% of your Apex code must be covered by unit tests. every unit test in your organization namespace is executed. ◊ Every trigger must have some test coverage. Instead. Salesforce production organizations must use the compileAndTest SOAP API call to make changes to Apex code. This should lead to 75% or more of your code being covered by unit tests. your focus shouldn't be on the percentage of code that is covered. For more information on runTests(). unless those errors are expected and caught in a try…catch block. Complete successfully without throwing any exceptions. Calls to System. the following must be true. and all of those tests must complete successfully. Always handle all exceptions that are caught. Use the runAs method to test your application in different user contexts. Note the following. you should make sure that every use case of your application is covered. execute each branch of code logic. Testing Best Practices Good tests should do the following: • Cover as many lines of code as possible. Classes defined with the isTest annotation do not count against your organization limit of 3 MB for all Apex code. such as na1. ◊ All classes and triggers must compile successfully. see SOAP API and SOAP Headers for Apex on page 624. Though administrators in a Salesforce production organization cannot make changes to Apex code using the Salesforce user interface. Before you can deploy Apex or package it for the Force. • • • • • • • In the case of conditional logic (including ternary operators).debug are not counted as part of Apex code coverage. see the WSDL located at https://your_salesforce_server/services/wsdl/apex.com AppExchange.com. Use the isTest annotation. instead of merely catching the exceptions. you won't need to delete any data. if you create an account A. ◊ Create all test data before calling the starttest method. as well as highlighting the lines of code that are not covered by tests in red. @isTest private class MileageTrackerTestSuite { static testMethod void runPositiveTestCases() { Double totalMiles = 0. you may need to test the classes in your organization individually. final Double u2Miles = 100. ◊ Since tests don't commit.com/index. final Double maxtotalMiles = 500. Testing Example The following example includes cases for the following types of tests: • • • Positive case with single and multiple records Negative case with single and multiple records Testing with other users The test is used with a simple mileage tracking application. The primary object is a custom object named Mileage__c. final Double singletotalMiles = 300. If you click the coverage percent number. Here is the entire test class. In the Salesforce user interface.php/Apex_Toolkit_for_Eclipse for details. Test the classes in your application individually. Never test your entire application in a single test.developerforce. • • Write comments stating not only what is supposed to be tested. highlighting the lines of code for that class or trigger that are covered by tests in blue. you may need to increase the Read timeout value for your Apex project. Set up test data: ◊ Create the necessary data in test classes. 157 . The existing code for the application verifies that not more than 500 miles are entered in a single day. Use the ORDER BY keywords to ensure that the records are returned in the expected order. The following sections step through specific portions of the code. For example. there is a Code Coverage column. so the tests do not have to rely on data in a particular organization. It also lists how many times a particular line in the class or trigger was executed by the test. and so on. and receive the ID 001D000000IEEmT. the ID of account B may or may not be sequentially higher. See https://wiki. the expected outcome. Record IDs are not created in ascending order unless you insert multiple records with the same request. consider the following: • • In the Force. then create account B. Not assume that record IDs are in sequential order. If you are running many tests.com IDE. • • On the list of Apex classes. a page displays. but the assumptions the tester made about the data. instead of trying to run all of the tests at the same time using the Run All Tests button.Testing Apex Testing Example • • • Exercise bulk trigger functionality—use at least 20 records in your tests. today()) ). insert testMiles1.today()). insert testMiles3.debug('Inserting 200 mileage records. for(Mileage__c m:[SELECT miles__c FROM Mileage__c WHERE CreatedDate = TODAY and CreatedById = :u2.debug('Inserting 300 miles..miles__c.assertEquals(singletotalMiles. (single record validation)').add( new Mileage__c(Miles__c = 1. //Run As U1 System. System.RunAs(u1){ System. totalMiles). for(Mileage__c m:[SELECT miles__c FROM Mileage__c WHERE CreatedDate = TODAY and CreatedById = :u1. Mileage__c testMiles1 = new Mileage__c(Miles__c = 300. } System. //Bulk validation totalMiles = 0. for(integer i=0.Id and miles__c != null]) { totalMiles += m..id and miles__c != null]) { totalMiles += m.. totalMiles). totalMiles).assertEquals(maxtotalMiles. (bulk validation)').Testing Apex Testing Example //Set up user User u1 = [SELECT Id FROM User WHERE Alias='auser'].assertEquals(u2Miles.RunAs(u2){ Mileage__c testMiles3 = new Mileage__c(Miles__c = 100. System. i++) { testMiles2. Date__c = System. } insert testMiles2. i<200. } System.miles__c. }//end RunAs(u1) //Validate additional user: totalMiles = 0. //Validate single insert for(Mileage__c m:[SELECT miles__c FROM Mileage__c WHERE CreatedDate = TODAY and CreatedById = :u1.today()). } //System.. Date__c = System.miles__c. Date__c = System. List<Mileage__c> testMiles2 = new List<Mileage__c>(). } //Validate System.RunAs(u2) } // runPositiveTestCases() 158 . //Setup RunAs User u2 = [SELECT Id FROM User WHERE Alias='tuser'].Id and miles__c != null]) { totalMiles += m. e. 3. } catch (DmlException e) { //Assert Error Message System.single record validation').contains('Insert failed. System. set the number of total miles back to 0: totalMiles = 0.debug('Inserting 300 more miles.assertEquals(Mileage__c. (negative test case)').today() ).assert( e.miles__c. Add text to the debug log.getDmlFields(0)[0]).today() ). e.getMessage() ). } //catch } //RunAs(u3) } // runNegativeTestCases() } // class MileageTrackerTestSuite Positive Test Case The following steps through the above code.. Use the system. } 4. Create a Mileage__c object and insert it into the database.debug('Inserting a record with 501 miles. 5. Validate the code by returning the inserted records: for(Mileage__c m:[SELECT miles__c FROM Mileage__c WHERE CreatedDate = TODAY and CreatedById = :createdbyId and miles__c != null]) { totalMiles += m. Before moving to the next test. Mileage__c testMiles3 = new Mileage__c( Miles__c = 501.getDmlStatusCode(0) ).assertEquals(singletotalMiles.. 159 ..Miles__c. first error: FIELD_CUSTOM_VALIDATION_EXCEPTION. 1. Date__c = System. the positive test case for single and multiple records. Mileage__c testMiles1 = new Mileage__c(Miles__c = 300. //Assert field System.assertEquals method to verify that the expected result is returned: System.assertEquals('FIELD_CUSTOM_VALIDATION_EXCEPTION' ..RunAs(u3){ System.Testing Apex Testing Example static testMethod void runNegativeTestCases() { User u3 = [SELECT Id FROM User WHERE Alias='tuser']. 2.getMessage(). totalMiles). //Assert Status Code System. e. try { insert testMiles3. indicating the next step of the code: System. insert testMiles1. Date__c = System. ' + 'Mileage request exceeds daily limit(500): [Miles__c]'). First exception on ' + 'row 0. in particular. today()). Date__c = System. Add text to the debug log.assertEquals to do the testing.assertEquals(maxtotalMiles.. } System. Create a Mileage__c record with 501 miles. First exception '+ 'on row 0. 3.assert(e. Add the following code to the catch block you previously created: //Assert Error Message System. negative test case').debug('Inserting 200 Mileage records. Negative Test Case The following steps through the above code. 7.assert and System. totalMiles).contains('Insert failed.assertEquals to verify that the expected result is returned: for(Mileage__c m:[SELECT miles__c FROM Mileage__c WHERE CreatedDate = TODAY and CreatedById = :CreatedbyId and miles__c != null]) { totalMiles += m. i++){ testMiles2.bulk validation'). 160 .add( new Mileage__c(Miles__c = 1. '+ 'Mileage request exceeds daily limit(500): [Miles__c]').getMessage(). 1.debug('Inserting 501 miles.Testing Apex Testing Example 6. e. 4. first error: FIELD_CUSTOM_VALIDATION_EXCEPTION. 8. add text to the debug log.miles__c. try { insert testMiles3. Mileage__c testMiles3 = new Mileage__c(Miles__c = 501.getMessage()). for(Integer i=0. indicating the next step of the code: System. } catch (DmlException e) { 5... indicating the next step of the code: System. Place the insert statement within a try/catch block. Now use the System. Then insert 200 Mileage__c records: List<Mileage__c> testMiles2 = new List<Mileage__c>(). Create a static test method called runNegativeTestCases: static testMethod void runNegativeTestCases(){ 2. Use System. i<200. Validate the code by creating a bulk insert of 200 records. This allows you to catch the validation exception and assert the generated error message. First. } insert testMiles2.today()) ). Date__c = System.. the negative test case. in particular. miles__c. 161 . in particular.assertEquals method to verify that the expected result is returned: System. indicating the next step of the code: System. Use the system.today()).getDmlFields(0)[0]). Add text to the debug log. Then insert one Mileage__c record: Mileage__c testMiles3 = new Mileage__c(Miles__c = 100. } } } . e. Validate the code by returning the inserted records: for(Mileage__c m:[SELECT miles__c FROM Mileage__c WHERE CreatedDate = TODAY and CreatedById = :u2.Miles__c. set the number of total miles back to 0: totalMiles = 0.assertEquals(u2Miles. Set up the next user. Date__c = System.Testing Apex Testing Example //Assert Field System. User u2 = [SELECT Id FROM User WHERE Alias='tuser']. System. 1. running as a second user. 4. 5.deleting any mileage records for ' + UserInfo. 2.assertEquals(Mileage__c.assertEquals('FIELD_CUSTOM_VALIDATION_EXCEPTION' e. Testing as a Second User The following steps through the above code.getDmlStatusCode(0)).getUserName() + ' from today'). totalMiles). Before moving to the next test. //Assert Status Code System.RunAs(u2){ 3.debug('Setting up testing . } 6.Id and miles__c != null]) { totalMiles += m. insert testMiles3. Chapter 6 Dynamic Apex In this chapter ... • • • • Understanding Apex Describe Information Dynamic SOQL Dynamic SOSL Dynamic DML Dynamic Apex enables developers to create more flexible applications by providing them with the ability to: • Access sObject and field describe information Describe information provides information about sObject and field properties. For example, the describe information for an sObject includes whether that type of sObject supports operations like create or undelete, the sObject's name and label, the sObject's fields and child objects, and so on. The describe information for a field includes whether the field has a default value, whether it is a calculated field, the type of the field, and so on. Note that describe information provides information about objects in an organization, not individual records. • Write dynamic SOQL queries, dynamic SOSL queries and dynamic DML Dynamic SOQL and SOSL queries provide the ability to execute SOQL or SOSL as a string at runtime, while dynamic DML provides the ability to create a record dynamically and then insert it into the database using DML. Using dynamic SOQL, SOSL, and DML, an application can be tailored precisely to the organization as well as the user's permissions. This can be useful for applications that are installed from Force.com AppExchange. 162 Dynamic Apex Understanding Apex Describe Information Understanding Apex Describe Information Apex provides two data structures for sObject and field describe information: • • Token—a lightweight, serializable reference to an sObject or a field that is validated at compile time. Describe result—an object that contains all the describe properties for the sObject or field. Describe result objects are not serializable, and are validated at runtime. It is easy to move from a token to its describe result, and vice versa. Both sObject and field tokens have the method getDescribe which returns the describe result for that token. On the describe result, the getSObjectType and getSObjectField methods return the tokens for sObject and field, respectively. Because tokens are lightweight, using them can make your code faster and more efficient. For example, use the token version of an sObject or field when you are determining the type of an sObject or field that your code needs to use. The token can be compared using the equality operator (==) to determine whether an sObject is the Account object, for example, or whether a field is the Name field or a custom calculated field. The following code provides a general example of how to use tokens and describe results to access information about sObject and field properties: // Create a new account as the generic type sObject sObject s = new Account(); // Verify that the generic sObject is an Account sObject System.assert(s.getsObjectType() == Account.sObjectType); // Get the sObject describe result for the Account object Schema.DescribeSObjectResult r = Account.sObjectType.getDescribe(); // Get the field describe result for the Name field on the Account object Schema.DescribeFieldResult f = Schema.sObjectType.Account.fields.Name; // Verify that the field token is the token for the Name field on an Account object System.assert(f.getSObjectField() == Account.Name); // Get the field describe result from the token f = f.getSObjectField().getDescribe(); The following algorithm shows how you can work with describe information in Apex: 1. 2. 3. 4. Generate a list or map of tokens for the sObjects in your organization (see Accessing All sObjects on page 166.) Determine the sObject you need to access. Generate the describe result for the sObject. If necessary, generate a map of field tokens for the sObject (see Accessing All Field Describe Results for an sObject on page 167.) 5. Generate the describe result for the field the code needs to access. Understanding Describe Information Permissions Apex generally runs in system mode. All classes and triggers that are not included in a package, that is, are native to your organization, have no restrictions on the sObjects that they can look up dynamically. This means that with native code, you can generate a map of all the sObjects for your organization, regardless of the current user's permission. Dynamic Apex, contained in managed packages created by salesforce.com ISV partners that are installed from Force.com AppExchange, have restricted access to any sObject outside the managed package. Partners can set the API Access value 163 Dynamic Apex Understanding Apex Describe Information within the package to grant access to standard sObjects not included as part of the managed package. While Partners can request access to standard objects, custom objects are not included as part of the managed package and can never be referenced or accessed by dynamic Apex that is packaged. For more information, see “About API and Dynamic Apex Access in Packages” in the Salesforce online help. Using sObject Tokens SObjects, such as Account and MyCustomObject__c, act as static classes with special static methods and member variables for accessing token and describe result information. You must explicitly reference an sObject and field name at compile time to gain access to the describe result. To access the token for an sObject, use one of the following methods: • • Access the sObjectType member variable on an sObject type, such as Account. Call the getSObjectType method on an sObject describe result, an sObject variable, a list, or a map. Schema.SObjectType is the data type for an sObject token. In the following example, the token for the Account sObject is returned: Schema.sObjectType t = Account.sObjectType; The following also returns a token for the Account sObject: Account A = new Account(); Schema.sObjectType T = A.getSObjectType(); This example can be used to determine whether an sObject or a list of sObjects is of a particular type: public class sObjectTest { { // Create a generic sObject variable s SObject s = Database.query('SELECT Id FROM Account LIMIT 1'); // Verify if that sObject variable is an Account token System.assertEquals(s.getSObjectType(), Account.sObjectType); // Create a list of generic sObjects List<sObject> l = new Account[]{}; // Verify if the list of sObjects contains Account tokens System.assertEquals(l.getSObjectType(), Account.sObjectType); } } Some standard sObjects have a field called sObjectType, for example, AssignmentRule, QueueSObject, and RecordType. For these types of sObjects, always use the getSObjectType method for retrieving the token. If you use the property, for example, RecordType.sObjectType, the field is returned. Using sObject Describe Results To access the describe result for an sObject, use one of the following methods: • • Call the getDescribe method on an sObject token. Use the Schema sObjectType static variable with the name of the sObject. For example, Schema.sObjectType.Lead. Schema.DescribeSObjectResult is the data type for an sObject describe result. 164 Dynamic Apex Understanding Apex Describe Information The following example uses the getDescribe method on an sObject token: Schema.DescribeSObjectResult D = Account.sObjectType.getDescribe(); The following example uses the Schema sObjectType static member variable: Schema.DescribeSObjectResult D = Schema.SObjectType.Account; For more information about the methods available with the sObject describe result, see sObject Describe Result Methods on page 349. Using Field Tokens To access the token for a field, use one of the following methods: • • Access the static member variable name of an sObject static type, for example, Account.Name. Call the getSObjectField method on a field describe result. The field token uses the data type Schema.SObjectField. In the following example, the field token is returned for the Account object's AccountNumber field: Schema.SObjectField F = Account.AccountNumber; In the following example, the field token is returned from the field describe result: // Get the describe result for the Name field on the Account object Schema.DescribeFieldResult f = Schema.sObjectType.Account.fields.Name; // Verify that the field token is the token for the Name field on an Account object System.assert(f.getSObjectField() == Account.Name); // Get the describe result from the token f = f.getSObjectField().getDescribe(); Using Field Describe Results To access the describe result for a field, use one of the following methods: • • Call the getDescribe method on a field token. Access the fields member variable of an sObject token with a field member variable (such as Name, BillingCity, and so on.) The field describe result uses the data type Schema.DescribeFieldResult. The following example uses the getDescribe method: Schema.DescribeFieldResult F = Account.AccountNumber.getDescribe(); This example uses the fields member variable method: Schema.DescribeFieldResult F = Schema.SObjectType.Account.fields.Name; In the example above, the system uses special parsing to validate that the final member variable (Name) is valid for the specified sObject at compile time. When the parser finds the fields member variable, it looks backwards to find the name of the sObject (Account) and validates that the field name following the fields member variable is legitimate. The fields member variable only works when used in this manner. 165 Dynamic Apex Understanding Apex Describe Information You can only have 100 fields member variable statements in an Apex class or trigger. Note: You should not use the fields member variable without also using either a field member variable name or the getMap method. For more information on getMap, see Accessing All Field Describe Results for an sObject on page 167. For more information about the methods available with a field describe result, see Describe Field Result Methods on page 353. Accessing All sObjects Use the Schema getGlobalDescribe method to return a map that represents the relationship between all sObject names (keys) to sObject tokens (values). For example: Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe(); The map has the following characteristics: • • • • It is dynamic, that is, it is generated at runtime on the sObjects currently available for the organization, based on permissions. The sObject names are case insensitive. The keys use namespaces as required. The keys reflect whether the sObject is a custom object. For example, if the code block that generates the map is in namespace N1, and an sObject is also in N1, the key in the map is represented as MyObject__c. However, if the code block is in namespace N1, and the sObject is in namespace N2, the key is N2__MyObject__c. In addition, standard sObjects have no namespace prefix. Note: If the getGlobalDescribe method is called from an installed managed package, it returns sObject names and tokens for Chatter sObjects, such as NewsFeed and UserProfileFeed, even if Chatter is not enabled in the installing organization. This is not true if the getGlobalDescribe method is called from a class not within an installed managed package. Creating sObjects Dynamically You can create sObjects whose types are determined at run time by calling the newSObject method of the Schema.sObjectType sObject token class. The following example shows how to get an sObject token that corresponds to an sObject type name using the Schema.getGlobalDescribe method. Then, an instance of the sObject is created through the newSObject method of Schema.sObjectType. This example also contains a test method that verifies the dynamic creation of an account. public class DynamicSObjectCreation { public static sObject createObject(String typeName) { Schema.SObjectType targetType = Schema.getGlobalDescribe().get(typeName); if (targetType == null) { // throw an exception } // Instantiate an sObject with the type passed in as an argument // at run time. return targetType.newSObject(); } static testmethod void testObjectCreation() { String typeName = 'Account'; String acctName = 'Acme'; 166 Dynamic Apex Understanding Apex Describe Information // Create a new sObject by passing the sObject type as an argument. Account a = (Account)createObject(typeName); System.assertEquals(typeName, String.valueOf(a.getSobjectType())); // Set the account name and insert the account. a.Name = acctName; insert a; // Verify the new sObject got inserted. Account[] b = [SELECT Name from Account WHERE Name = :acctName]; system.assert(b.size() > 0); } } Accessing All Field Describe Results for an sObject Use the field describe result's getMap method to return a map that represents the relationship between all the field names (keys) and the field tokens (values) for an sObject. The following example generates a map that can be used to access a field by name: Map<String, Schema.SObjectField> M = Schema.SObjectType.Account.fields.getMap(); Note: The value type of this map is not a field describe result. Using the describe results would take too many system resources. Instead, it is a map of tokens that you can use to find the appropriate field. After you determine the field, generate the describe result for it. The map has the following characteristics: • • • • It is dynamic, that is, it is generated at runtime on the fields for that sObject. All field names are case insensitive. The keys use namespaces as required. The keys reflect whether the field is a custom object. For example, if the code block that generates the map is in namespace N1, and a field is also in N1, the key in the map is represented as MyField__c. However, if the code block is in namespace N1, and the field is in namespace N2, the key is N2__MyField__c. In addition, standard fields have no namespace prefix. Note: A field describe executed from within an installed managed package returns Chatter fields even if Chatter is not enabled in the installing organization. This is not true if the field describe is executed from a class not within an installed managed package. Accessing All Data Categories Associated with an sObject Use the describeDataCategory Groups and describeDataCategory GroupStructures methods to return the categories associated with a specific object: 1. Return all the category groups associated with the objects of your choice (see describeDataCategory Groups on page 340). 2. From the returned map, get the category group name and sObject name you want to further interrogate (see Schema.Describe DataCategoryGroupResult on page 342). 3. Specify the category group and associated object, then retrieve the categories available to this object (see describeDataCategory GroupStructures on page 341). The describeDataCategory GroupStructures method returns the categories available for the object in the category group you specified. For additional information about data categories, see “What are Data Categories?” in the Salesforce online help. 167 Dynamic Apex Understanding Apex Describe Information In the following example, the describeDataCategoryGroupSample method returns all the category groups associated with the Article and Question objects. The describeDataCategoryGroupStructures method returns all the categories available for articles and questions in the Regions category group. For additional information about articles and questions, see “Managing Articles and Translations” and “Answers Overview” in the Salesforce online help. To use the following example, you must: • • • • • Enable Salesforce Knowledge. Enable the answers feature. Create a data category group called Regions. Assign Regions as the data category group to be used by Answers. Make sure the Regions data category group is assigned to Salesforce Knowledge. For more information on creating data category groups, see “Creating and Modifying Category Groups” in the Salesforce online help. For more information on answers, see “Answers Overview” in the Salesforce online help. public class DescribeDataCategoryGroupSample { public static List<DescribeDataCategoryGroupResult> describeDataCategoryGroupSample(){ List<DescribeDataCategoryGroupResult> describeCategoryResult; try { //Creating the list of sobjects to use for the describe //call List<String> objType = new List<String>(); objType.add('KnowledgeArticleVersion'); objType.add('Question'); //Describe Call describeCategoryResult = Schema.describeDataCategoryGroups(objType); //Using the results and retrieving the information for(DescribeDataCategoryGroupResult singleResult : describeCategoryResult){ //Getting the name of the category singleResult.getName(); //Getting the name of label singleResult.getLabel(); //Getting description singleResult.getDescription(); //Getting the sobject singleResult.getSobject(); } } catch(Exception e){ } return describeCategoryResult; } } public class DescribeDataCategoryGroupStructures { public static List<DescribeDataCategoryGroupStructureResult> getDescribeDataCategoryGroupStructureResults(){ List<DescribeDataCategoryGroupResult> describeCategoryResult; List<DescribeDataCategoryGroupStructureResult> describeCategoryStructureResult; try { //Making the call to the describeDataCategoryGroups to //get the list of category groups associated List<String> objType = new List<String>(); 168 Dynamic Apex Understanding Apex Describe Information objType.add('KnowledgeArticleVersion'); objType.add('Question'); describeCategoryResult = Schema.describeDataCategoryGroups(objType); //Creating a list of pair objects to use as a parameter //for the describe call List<DataCategoryGroupSobjectTypePair> pairs = new List<DataCategoryGroupSobjectTypePair>(); //Looping throught the first describe result to create //the list of pairs for the second describe call for(DescribeDataCategoryGroupResult singleResult : describeCategoryResult){ DataCategoryGroupSobjectTypePair p = new DataCategoryGroupSobjectTypePair(); p.setSobject(singleResult.getSobject()); p.setDataCategoryGroupName(singleResult.getName()); pairs.add(p); } //describeDataCategoryGroupStructures() describeCategoryStructureResult = Schema.describeDataCategoryGroupStructures(pairs, false); //Getting data from the result for(DescribeDataCategoryGroupStructureResult singleResult : describeCategoryStructureResult){ //Get name of the associated Sobject singleResult.getSobject(); //Get the name of the data category group singleResult.getName(); //Get the name of the data category group singleResult.getLabel(); //Get the description of the data category group singleResult.getDescription(); //Get the top level categories DataCategory [] toplevelCategories = singleResult.getTopCategories(); //Recursively get all the categories List<DataCategory> allCategories = getAllCategories(toplevelCategories); for(DataCategory category : allCategories) { //Get the name of the category category.getName(); //Get the label of the category category.getLabel(); //Get the list of sub categories in the category DataCategory [] childCategories = category.getChildCategories(); } } } catch (Exception e){ } return describeCategoryStructureResult; } private static DataCategory[] getAllCategories(DataCategory [] categories){ if(categories.isEmpty()){ return new DataCategory[]{}; 169 Dynamic Apex Understanding Apex Describe Information } else { DataCategory [] categoriesClone = categories.clone(); DataCategory category = categoriesClone[0]; DataCategory[] allCategories = new DataCategory[]{category}; categoriesClone.remove(0); categoriesClone.addAll(category.getChildCategories()); allCategories.addAll(getAllCategories(categoriesClone)); return allCategories; } } } Testing Access to All Data Categories Associated with an sObject The following example tests the describeDataCategoryGroupSample method shown in Accessing All Data Categories Associated with an sObject. It ensures that the returned category group and associated objects are correct. @isTest private class DescribeDataCategoryGroupSampleTest { public static testMethod void describeDataCategoryGroupSampleTest(){ List<DescribeDataCategoryGroupResult>describeResult = DescribeDataCategoryGroupSample.describeDataCategoryGroupSample(); //Assuming that you have KnowledgeArticleVersion and Questions //associated with only one category group 'Regions'. System.assert(describeResult.size() == 2, 'The results should only contain two results: ' + describeResult.size()); for(DescribeDataCategoryGroupResult result : describeResult) { //Storing the results String name = result.getName(); String label = result.getLabel(); String description = result.getDescription(); String objectNames = result.getSobject(); //asserting the values to make sure System.assert(name == 'Regions', 'Incorrect name was returned: ' + name); System.assert(label == 'Regions of the World', 'Incorrect label was returned: ' + label); System.assert(description == 'This is the category group for all the regions', 'Incorrect description was returned: ' + description); System.assert(objectNames.contains('KnowledgeArticleVersion') || objectNames.contains('Question'), 'Incorrect sObject was returned: ' + objectNames); } } } This example tests the describeDataCategoryGroupStructures method shown in Accessing All Data Categories Associated with an sObject. It ensures that the returned category group, categories and associated objects are correct. @isTest private class DescribeDataCategoryGroupStructuresTest { public static testMethod void getDescribeDataCategoryGroupStructureResultsTest(){ List<Schema.DescribeDataCategoryGroupStructureResult> describeResult = DescribeDataCategoryGroupStructures.getDescribeDataCategoryGroupStructureResults(); System.assert(describeResult.size() == 2, 'The results should only contain 2 results: ' + describeResult.size()); //Creating category info 170 Dynamic Apex Understanding Apex Describe Information CategoryInfo world = new CategoryInfo('World', 'World'); CategoryInfo asia = new CategoryInfo('Asia', 'Asia'); CategoryInfo northAmerica = new CategoryInfo('NorthAmerica', 'North America'); CategoryInfo southAmerica = new CategoryInfo('SouthAmerica', 'South America'); CategoryInfo europe = new CategoryInfo('Europe', 'Europe'); List<CategoryInfo> info = new CategoryInfo[] { asia, northAmerica, southAmerica, europe }; for (Schema.DescribeDataCategoryGroupStructureResult result : describeResult) { String name = result.getName(); String label = result.getLabel(); String description = result.getDescription(); String objectNames = result.getSobject(); //asserting the values to make sure System.assert(name == 'Regions', 'Incorrect name was returned: ' + name); System.assert(label == 'Regions of the World', 'Incorrect label was returned: ' + label); System.assert(description == 'This is the category group for all the regions', 'Incorrect description was returned: ' + description); System.assert(objectNames.contains('KnowledgeArticleVersion') || objectNames.contains('Question'), 'Incorrect sObject was returned: ' + objectNames); DataCategory [] topLevelCategories = result.getTopCategories(); System.assert(topLevelCategories.size() == 1, 'Incorrect number of top level categories returned: ' + topLevelCategories.size()); System.assert(topLevelCategories[0].getLabel() == world.getLabel() && topLevelCategories[0].getName() == world.getName()); //checking if the correct children are returned DataCategory [] children = topLevelCategories[0].getChildCategories(); System.assert(children.size() == 4, 'Incorrect number of children returned: ' + children.size()); for(Integer i=0; i < children.size(); i++){ System.assert(children[i].getLabel() == info[i].getLabel() && children[i].getName() == info[i].getName()); } } } private class CategoryInfo { private final String name; private final String label; private CategoryInfo(String n, String l){ this.name = n; this.label = l; } public String getName(){ return this.name; } public String getLabel(){ return this.label; } } } 171 Dynamic Apex Dynamic SOQL Dynamic SOQL Dynamic SOQL refers to the creation of a SOQL string at runtime with Apex code. Dynamic SOQL enables you to create more flexible applications. For example, you can create a search based on input from an end user, or update records with varying field names. To create a dynamic SOQL query at runtime, use the database query method, in one of the following ways: • Return a single sObject when the query returns a single record: sObject S = Database.query(string_limit_1); • Return a list of sObjects when the query returns more than a single record: List<sObject> L = Database.query(string); The database query method can be used wherever an inline SOQL query can be used, such as in regular assignment statements and for loops. The results are processed in much the same way as static SOQL queries are processed. Dynamic SOQL results can be specified as concrete sObjects, such as Account or MyCustomObject__c, or as the generic sObject data type. At runtime, the system validates that the type of the query matches the declared type of the variable. If the query does not return the correct sObject type, a runtime error is thrown. This means you do not need to cast from a generic sObject to a concrete sObject. Dynamic SOQL queries have the same governor limits as static queries. For more information on governor limits, see Understanding Execution Governors and Limits on page 214. For a full description of SOQL query syntax, see Salesforce Object Query Language (SOQL) in the Force.com SOQL and SOSL Reference. SOQL Injection SOQL injection is a technique by which a user causes your application to execute database methods you did not intend by passing SOQL statements into your code. This can occur in Apex code whenever your application relies on end user input to construct a dynamic SOQL statement and you do not handle the input properly. To prevent SOQL injection, use the escapeSingleQuotes method. This method adds the escape character (\) to all single quotation marks in a string that is passed in from a user. The method ensures that all single quotation marks are treated as enclosing strings, instead of database commands. Dynamic SOSL Dynamic SOSL refers to the creation of a SOSL string at runtime with Apex code. Dynamic SOSL enables you to create more flexible applications. For example, you can create a search based on input from an end user, or update records with varying field names. To create a dynamic SOSL query at runtime, use the search query method. For example: List<List <sObject>> myQuery = search.query(SOSL_search_string); 172 Dynamic Apex Dynamic DML The following example exercises a simple SOSL query string. String searchquery='FIND\'Edge*\'IN ALL FIELDS RETURNING Account(id,name),Contact, Lead'; List<List<SObject>>searchList=search.query(searchquery); Dynamic SOSL statements evaluate to a list of lists of sObjects, where each list contains the search results for a particular sObject type. The result lists are always returned in the same order as they were specified in the dynamic SOSL query. From the example above, the results from Account are first, then Contact, then Lead. The search query method can be used wherever an inline SOSL query can be used, such as in regular assignment statements and for loops. The results are processed in much the same way as static SOSL queries are processed. Dynamic SOSL queries have the same governor limits as static queries. For more information on governor limits, see Understanding Execution Governors and Limits on page 214. For a full description of SOSL query syntax, see Salesforce Object Search Language (SOSL) in the Force.com SOQL and SOSL Reference. SOSL Injection SOSL injection is a technique by which a user causes your application to execute database methods you did not intend by passing SOSL statements into your code. This can occur in Apex code whenever your application relies on end user input to construct a dynamic SOSL statement and you do not handle the input properly. To prevent SOSL injection, use the escapeSingleQuotes method. This method adds the escape character (\) to all single quotation marks in a string that is passed in from a user. The method ensures that all single quotation marks are treated as enclosing strings, instead of database commands. Dynamic DML In addition to querying describe information and building SOQL queries at runtime, you can also create sObjects dynamically, and insert them into the database using DML. To create a new sObject of a given type, use the newSObject method on an sObject token. Note that the token must be cast into a concrete sObject type (such as Account). For example: // Get a new account Account A = new Account(); // Get the token for the account Schema.sObjectType tokenA = A.getSObjectType(); // The following produces an error because the token is a generic sObject, not an Account // Account B = tokenA.newSObject(); // The following works because the token is cast back into an Account Account B = (Account)tokenA.newSObject(); Though the sObject token tokenA is a token of Account, it is considered an sObject because it is accessed separately. It must be cast back into the concrete sObject type Account to use the newSObject method. For more information on casting, see Classes and Casting on page 134. 173 Dynamic Apex Dynamic DML This is another example that shows how to obtain the sObject token through the Schema.getGlobalDescribe method and then creates a new sObject using the newSObject method on the token. This example also contains a test method that verifies the dynamic creation of an account. public class DynamicSObjectCreation { public static sObject createObject(String typeName) { Schema.SObjectType targetType = Schema.getGlobalDescribe().get(typeName); if (targetType == null) { // throw an exception } // Instantiate an sObject with the type passed in as an argument // at run time. return targetType.newSObject(); } static testmethod void testObjectCreation() { String typeName = 'Account'; String acctName = 'Acme'; // Create a new sObject by passing the sObject type as an argument. Account a = (Account)createObject(typeName); System.assertEquals(typeName, String.valueOf(a.getSobjectType())); // Set the account name and insert the account. a.Name = acctName; insert a; // Verify the new sObject got inserted. Account[] b = [SELECT Name from Account WHERE Name = :acctName]; system.assert(b.size() > 0); } } You can also specify an ID with newSObject to create an sObject that references an existing record that you can update later. For example: SObject s = Database.query('SELECT Id FROM account LIMIT 1')[0].getSObjectType(). newSObject([SELECT Id FROM Account LIMIT 1][0].Id); See Schema.sObjectType on page 359. Setting and Retrieving Field Values Use the get and put methods on an object to set or retrieve values for fields using either the API name of the field expressed as a String, or the field's token. In the following example, the API name of the field AccountNumber is used: SObject s = [SELECT AccountNumber FROM Account LIMIT 1]; Object o = s.get('AccountNumber'); s.put('AccountNumber', 'abc'); The following example uses the AccountNumber field's token instead: Schema.DescribeFieldResult f = Schema.sObjectType.Account.fields.AccountNumber; Sobject s = Database.query('SELECT AccountNumber FROM Account LIMIT 1'); s.put(f.getsObjectField(), '12345'); The Object scalar data type can be used as a generic data type to set or retrieve field values on an sObject. This is equivalent to the anyType field type. Note that the Object data type is different from the sObject data type, which can be used as a generic type for any sObject. 174 LastName FROM Contacts LIMIT 1) FROM Account'. // Prevent a null relationship from being accessed SObject[] childRecordsFromParent = parentRecord. You do not need the ID of the 'xxx' record. If you had assigned a value to the ID for c2__r.query('SELECT Id. For example: insert new C1__c(name = 'x'. use the get or put methods. if (childRecordsFromParent != null) { for (SObject childRecord : childRecordsFromParent){ Object ChildFieldValue1 = childRecord.getSObject('Account'). Note that these methods must be used with the sObject data type. The following example shows how to get the values from a subquery in a parent-to-child relationship using dynamic Apex: String queryString = 'SELECT Id.get('LastName'). suppose that custom object C1 has a foreign key c2__c that links to a child custom object C2. it would be ignored. not the record. Object ChildFieldValue2 = childRecord. To set or retrieve the record associated with a foreign key. SObject a = c. Setting and Retrieving Foreign Keys Apex supports populating foreign keys by name (or external ID) in the same way as the API. Apex assumes the foreign key is populated through a relationship SOQL query. c2__r = new C2__c(name = 'xxx')). You want to create a C1 object and have it associated with a C2 record named 'xxx' (assigned to the value c2__r). for (SObject parentRecord : queryParentObject){ Object ParentFieldValue = parentRecord. not Object. Account.get('Name'). For example. it is ignored by the DML operation. If you do have the ID.debug('Account Name: ' + ParentFieldValue + '. SObject[] queryParentObject = Database. AccountId.get('FirstName'). use the getSObject and putSObject methods. There is no need to specify the external ID for a parent sObject value while working with child sObjects.Name FROM Contact LIMIT 1'). You can also access foreign keys using dynamic Apex. Name. } } } 175 . use it with the child object. assign it to the object (c2__c).Dynamic Apex Dynamic DML Note: Apex classes and triggers saved (compiled) using API version 15. If you have an ID. as it is populated through the relationship of parent to child. For example: SObject c = Database.getSObjects('Contacts'). System. which always returns a parent object with a populated ID. To set or retrieve the scalar ID value of a foreign key. FirstName.0 and higher produce a runtime error if you assign a String value that is too long for the field.query(queryString). Contact Name: '+ ChildFieldValue1 + ' ' + ChildFieldValue2). ' + '(SELECT FirstName. If you provide an ID in the parent sObject. Batch jobs can also be programmatically scheduled to run at specific times using the Apex scheduler. For more information on the Schedule Apex page. mass record changes through the user interface. Or a developer could build a data cleansing operation that goes through all Accounts and Opportunities on a nightly basis and updates them if necessary. In particular. a developer could build an archiving solution that runs on a nightly basis. For example. 176 . You must be able to guarantee that the trigger will not add more batch jobs than the five that are allowed.. Batch jobs can be programmatically invoked at runtime using Apex. You can evaluate your current count by viewing the Scheduled Jobs page in Salesforce or programmatically using SOAP API to query the AsyncapexJob object. and all cases where more than one record can be updated at a time. see Understanding Apex Managed Sharing on page 186. import wizards.. For more information on batch jobs. or scheduled using the Schedule Apex page in the Salesforce user interface. continue to Using Batch Apex on page 177. For more information on Apex managed sharing. The batch Apex interface is also used for Apex managed sharing recalculations. consider API bulk updates. see “Scheduling Apex” in the Salesforce online help. long-running processes on the Force.com platform.Chapter 7 Batch Apex In this chapter . You can only have five queued or active batch jobs at one time. looking for records past a certain date and adding them to an archive. • • Using Batch Apex Understanding Apex Managed Sharing A developer can now employ batch Apex to build complex. based on custom criteria. Batch Apex is exposed as an interface that must be implemented by the developer. Warning: Use extreme care if you are planning to invoke a batch job from a trigger. Batchable interface contains three methods that must be implemented: • start method global (Database.Batchable. or a list of parameterized types.BatchableContext BC){} The finish method is called after all batches are processed. 177 . the governor limit for the total number of records retrieved by SOQL queries is bypassed. For more information. To monitor or stop the execution of the batch Apex job. You can also use the iterable to create your own custom process for iterating through the list.BatchableContext object. Use this method to send confirmation emails or execute post-processing operations. This method takes the following: ◊ A reference to the Database.QueryLocator. If you use a querylocator object. Batches of records are not guaranteed to execute in the order they are received from the start method. • execute method: global void execute(Database. If you are using a Database.QueryLocator object when you are using a simple query (SELECT) to generate the scope of objects used in the batch job.Batchable Interface The Database. Use this method to do all required processing for each chunk of data. click Your Name > Setup > Monitoring > Apex Jobs. a batch Apex job for the Account object can return a QueryLocator for all account records (up to 50 million records) in an organization. Use the Database. and then invoke the class programmatically. see Monitoring the Apex Job Queue in the Salesforce online help. the governor limit for the total number of records retrieved by SOQL queries is still enforced. list<P>){} The execute method is called for each batch of records passed to the method. ◊ A list of sObjects.BatchableContext bc) {} The start method is called at the beginning of a batch Apex job. the returned list should be used. Use the start method to collect the records or objects to be passed to the interface method execute. such as List<sObject>. Implementing the Database. This method returns either a Database. For example.Batch Apex Using Batch Apex Using Batch Apex To use batch Apex. Use the iterable when you need to create a complex scope for the batch job.QueryLocator object or an iterable that contains the records or objects being passed into the job.QueryLocator | Iterable<sObject>) start(Database.BatchableContext BC. you must write an Apex class that implements the Salesforce-provided interface Database. • finish method global void finish(Database. Important: If you use an iterable. Another example is a sharing recalculation for the Contact object that returns a QueryLocator for all account records in an organization. Batchable<sObject>{ global global global global final final final final String String String String Query. The following example uses a Database. TotalJobItems.getJobId()]. Entity.000 records and is executed without the optional scope parameter from Database. mail.setPlainTextBody ('The batch Apex job processed ' + a.QueryLocator: global class SearchAndReplace implements Database. String f. String v){ Query=q. The Apex governor limits are reset for each transaction. // Send an email to the Apex job's submitter notifying of job completion.BatchableContext BC){ // Get the ID of the AsyncApexJob representing this batch job // from Database. mail.TotalJobItems + ' batches with '+ a. } Using Database. If the first transaction succeeds but the second fails.Status). String e.Email FROM AsyncApexJob WHERE Id = :BC. mail. global SearchAndReplace(String q.BatchableContext object: Name getJobID Arguments Returns ID Description Returns the ID of the AsyncApexJob object associated with this batch job as a string. Entity=e. Use this method to track the progress of records in the batch job.BatchableContext All of the methods in the Database.QueryLocator to Define Scope The start method can return either a Database. Messaging.setSubject('Apex Sharing Recalculation ' + a.Batchable interface require a reference to a Database. global void finish(Database. You can also use this ID with the System. Field. Use this object to track the progress of the batch job.Email}. // Query the AsyncApexJob object to retrieve the current job's information. String[] toAddresses = new String[] {a. Field=f. Value.').CreatedBy.SingleEmailMessage mail = new Messaging.BatchableContext object. CreatedBy.BatchableContext.Batch Apex Using Batch Apex Each execution of a batch Apex job is considered a discrete transaction. The following is the instance method with the Database. the database updates made in the first transaction are not rolled back. Messaging.BatchableContext to query the AsyncApexJob associated with the batch job. The following example uses the Database. } 178 .Value=v.setToAddresses(toAddresses). JobItemsProcessed. Status. AsyncApexJob a = [SELECT Id. a batch Apex job that contains 1.executeBatch is considered five transactions of 200 records each. NumberOfErrors.NumberOfErrors + ' failures.SingleEmailMessage[] { mail }). Using Database.QueryLocator object that contains the records to be used in the batch job or an iterable.abortJob method.sendEmail(new Messaging.SingleEmailMessage(). For example. This parameter specifies the number of records that should be passed into the execute method. } update accsToUpdate. accsToUpdate. Salesforce chunks the records returned by the QueryLocator into smaller batches of up to 2.Name = 'true'. a.BatchableContext info.put(Field. By limiting the number of records.BatchableContext info){ return new CustomAccountIterable().executeBatch method to programmatically begin a batch job. Important: When you call Database. or an iterable.000. } global void finish(Database. however. the optional scope parameter of Database.BatchableContext info){ } } Using the Database.getQueryLocator(query).add(a). If the start method returns a QueryLocator.BatchableContext BC){ return Database.QueryLocator object that contains the records to be used in the batch job.batchable{ global Iterable start(Database. } global void execute(Database. 179 . the scope parameter value has no upper limit. Actual execution may be delayed based on service availability. List<sObject> scope){ for(sobject s : scope){ s. } global void finish(Database. The Database. Use an iterable to step through the returned items more easily. Salesforce only adds the process to the queue at the scheduled time.Batch Apex Using Batch Apex global Database. } update scope.executeBatch method takes two parameters: • • The class that implements Database.executeBatch Method You can use the Database. if you use a very high number. The Database. you are thereby limiting the operations per transaction.executeBatch. for(Account a : scope){ a. If set to a higher value.Batchable. Use this parameter when you have many operations for each record being passed in and are running into governor limits.BatchableContext BC. you may run into other limits.NumberOfEmployees = 70. } global void execute(Database. global class batchClass implements Database. If the start method returns an iterable.executeBatch method takes an optional parameter scope.BatchableContext BC){ } } Using an Iterable in Batch Apex to Define Scope The start method can return either a Database. This value must be greater than zero. List<Account> scope){ List<Account> accsToUpdate = new List<Account>().000 records.Value).executeBatch can have a maximum value of 2.QueryLocator start(Database. The following class uses batch Apex to reassign all accounts owned by a specific user to a different user. List<sObject> scope){ List<Account> accns = new List<Account>().executeBatch(reassign).e. List<sObject> scope){ for(Sobject s : scope){s. String email.Value=v. Id fromUserId.QueryLocator: global class UpdateAccountFields implements Database. For more information about the AsyncApexJob object.Value). for(sObject s : scope){Account a = (Account)s.executeBatch method returns the ID of the AsyncApexJob object. global final String Entity.executeBatch(new UpdateAccountFields(q.QueryLocator start(Database. global final String Value. Id toUserId.BatchableContext BC){ } } The following code can be used to call the above class: Id batchInstanceId = Database. String v){ Query=q. } global void execute(Database. global UpdateAccountFields(String q. JobItemsProcessed. TotalJobItems. String f.BatchableContext BC. } update scope. Batch Apex Examples The following example uses a Database. global class OwnerReassignment implements Database. Status.querylocator start(Database.v).Batchable<sObject>{ String query.getQueryLocator(query). NumberOfErrors FROM AsyncApexJob WHERE ID =: batchprocessid ]. String e.getQueryLocator(query). 180 . Entity=e. You can also use this ID with the System.put(Field. Field=f.com.BatchableContext BC. For example: ID batchprocessid = Database.Batchable<sObject>{ global final String Query. global Database.Batch Apex Using Batch Apex The Database.f. } global void finish(Database. AsyncApexJob aaj = [SELECT Id. see AsyncApexJob in the Object Reference for Salesforce and Force. global final String Field. which can then be used to track the progress of the job. 5).BatchableContext BC){ return Database. } global Database.} global void execute(Database.BatchableContext BC){ return Database.abortJob method. format('yyyy-MM-dd')+'T'+ d. mail.com'). Messaging.OwnerId=toUserId. mail.SingleEmailMessage[] { mail }).emptyRecycleBin(scope).000Z'. reassign.Batch Apex Using Batch Apex if(a. BatchDelete BDel = new BatchDelete().setSubject('Batch Process Completed'). reassign. mail.sendEmail(new Messaging.BatchableContext BC){ Messaging. } global void finish(Database. reassign. The specified query selects documents to delete for all documents that are in a specified folder and that are older than a specified date.id + '\''. d = d. mail. // Replace this value with the folder ID that contains // the documents to delete.toUserId = u2.query = 'SELECT Id FROM Document WHERE FolderId=\'' + folderId + '\' AND CreatedDate < '+d.com'.SingleEmailMessage().executeBatch(reassign). 181 . accns. Datetime d = Datetime.OwnerId==fromUserId){ a.setSenderDisplayName('Batch Processing').format('HH:mm')+':00. Ownerid FROM Account ' + 'WHERE ownerid=\'' + u.Batchable<sObject> { public String query. mail. ID batchprocessid = Database.setReplyTo('batch@acme. Name.BatchableContext BC. } } update accns. } global void execute(Database.BatchableContext BC){ return Database. String folderId = '00lD000000116lD'. global Database. // Query for selecting the documents to delete BDel. The following is an example of a batch Apex class for deleting records. global class BatchDelete implements Database.SingleEmailMessage mail = new Messaging. List<sObject> scope){ delete scope. reassign.QueryLocator start(Database. the sample invokes the batch job.setToAddresses(new String[] {email}).BatchableContext BC){ } } This code calls the BatchDelete batch Apex class to delete old documents. } } Use the following to execute the OwnerReassignment class in the previous example: OwnerReassignment reassign = new OwnerReassignment().email='admin@acme. } global void finish(Database.query = 'SELECT Id.now().setPlainTextBody('Batch Process has completed'). DataBase.fromUserId = u.getQueryLocator(query).add(a). Next.addDays(-1). global SummarizeAccountTotal(String q){Query=q. a batch Apex job that contains 1.Stateful in the class definition. Database.Stateful. } } global void finish(Database. Using State in Batch Apex Each execution of a batch Apex job is considered a discrete transaction.BatchableContext BC. List<sObject> scope){ for(sObject s : scope){ Summary = Integer. You can use this variable to share the initial state with all instances of the Database. System. For example: // Implement the interface using a list of Account sObjects // Note that the initialState variable is declared as final 182 .Stateful. The following example summarizes a custom field total__c as the records are processed: global class SummarizeAccountTotal implements Database. all static and instance member variables are set back to their original values.AllowsCallouts{ } Callouts include HTTP requests as well as methods defined with the webService keyword.debug('Returned batch process ID: ' + batchProcessId). suppose your job processed opportunity records. For example: global class SearchAndReplace implements Database.QueryLocator start(Database.AllowsCallouts in the class definition.executeBatch(BDel).Batchable methods. If you don't specify Database.BatchableContext BC){ } } In addition.get('total__c'))+Summary.valueOf(s.Batch Apex Using Batch Apex // Invoke the batch job.Stateful{ global final String Query. For example. you can maintain state across these transactions.000 records and is executed without the optional scope parameter is considered five transactions of 200 records each. global integer Summary.getQueryLocator(query). you can specify a variable to access the initial state of the class. only instance member variables retain their values between transactions.BatchableContext BC){ return Database. Summary = 0. } global void execute( Database. Maintaining state is useful for counting or summarizing records as they're processed. When using Database. } global Database. If you specify Database. For example. you must specify Database. Database. You could define a method in execute to aggregate totals of the opportunity amounts as they were processed. Static member variables don’t and are reset between transactions. ID batchprocessid = Database.Batchable<sObject>.Batchable<sObject>. Using Callouts in Batch Apex To use a callout in batch Apex. com API version 21. The executeBatch method starts an asynchronous process. Use the Test methods startTest and stopTest around the executeBatch method to ensure it finishes before continuing your test.getQueryLocator(query). Starting with Apex saved using Salesforce. global MyBatchable(String intialState) { this. The example below tests the OwnerReassignment class.id.com API version 25.QueryLocator start(Database. do not count against your limits for the number of queued jobs.com API version 22. you must make certain that the batch job is finished before testing against the results. the batch job executes at the end of your test method for Apex saved using Salesforce. For example. List<sObject> batch) { // Access initialState here } global void finish(Database. causes the test method to fail. such exceptions don't get passed to the test method and don't cause test methods to fail. If you want to handle exceptions in the test method.initialState = initialState. and as a result.BatchableContext BC) { // Access initialState here } } Note that initialState is the initial state of the class.BatchableContext BC. All asynchronous calls made after the startTest method are collected by the system. Note: Asynchronous calls.com']. When stopTest is executed. exceptions that occur during the execution of a batch Apex job that is invoked by a test method are now passed to the calling test method. If you don’t include the executeBatch method within the startTest and stopTest methods. the second chunk of processed records would not be able to access the new value: only the initial value would be accessible.BatchableContext BC) { // Access initialState here return Database. if you changed the value of initialState in execute. called in a startTest. such as @future or executeBatch.Batchable<sObject> { private final String initialState. String query. you can test only one execution of the execute method.0 and later. public static testMethod void testBatch() { user u = [SELECT ID.com']. You cannot use it to pass information between instances of the class during execution of the batch job. } global Database.0 and earlier. enclose the code in try and catch statements. Note however that with Apex saved using Salesforce. This means that when you test batch Apex. String u2id = u2. UserName FROM User WHERE username='testuser2@acme. } global void execute(Database. all asynchronous processes are run synchronously. You can use the scope parameter of the executeBatch method to limit the number of records passed into the execute method to ensure that you aren't running into governor limits. user u2 = [SELECT ID. 183 .Batch Apex Using Batch Apex global class MyBatchable implements Database. stopTest block. You must place the catch block after the stopTest method. UserName FROM User WHERE username='testuser1@acme. Testing Batch Apex When testing your batch Apex. but not in earlier versions.0. i<200.StopTest(). 50 batch cursors. you can have 50 Apex query cursors. the batch job is immediately terminated and marked as Failed.add(a). List <Account> accns = new List<Account>(). The start. reassign.executeBatch(reassign). reassign.Id + '\'' + ' LIMIT 200'. A user can have up to 50 query cursors open at a time. for(integer i = 0. if 50 cursors are open and a client application still logged in as the same user attempts to open a new one. if you use a very high number.the Salesforce.fromUserId = u. // Important .StartTest(). If more than 50 million records are returned. • • A maximum of 50 million records can be returned in the Database. and then passes each batch to the execute method.000 records. however.ID).countquery('SELECT COUNT()' +' FROM Account WHERE OwnerId=\'' + u2. Test.com features are tracked separately. the optional scope parameter of Database. the oldest of the 50 cursors is released. Note that this limit is different for the batch Apex start method.this simulates one execute.com'. reassign.com test framework only allows you to // test one execute. Ownerid ' + 'FROM Account ' + 'WHERE OwnerId=\'' + u. i++){ Account a = new Account(Name='testAccount'+'i'. For example. OwnerReassignment reassign = new OwnerReassignment(). accns. The other batch Apex methods have the higher limit of 50 cursors.Batch Apex Using Batch Apex // Create 200 test accounts . If set to a higher value.query='SELECT ID.000 per 24 hours. If the start method returns an iterable. the scope parameter value has no upper limit. The maximum number of batch executions is 250.executeBatch. execute. reassign.toUserId = u2. } } Batch Apex Governor Limits Keep in mind the following governor limits for batch Apex: • • Up to five queued or active batch jobs are allowed for Apex. Test. which can have up to five query cursors open at a time per user.QueryLocator object. Salesforce chunks the records returned by the start method into batches of 200. Batch executions are limited to 10 callouts per method execution. Name.executeBatch can have a maximum value of 2.Id + '\'').000. and finish methods can implement up to 10 callouts each.email='admin@acme. 200). • • • • 184 . Salesforce chunks the records returned by the QueryLocator into smaller batches of up to 2. Apex governor limits are reset for each execution of execute. Ownerid = u. you may run into other limits. If no size is specified with the optional scope parameter of Database. System.Id. } insert accns. ID batchprocessid = Database. Cursor limits for different Force. If the start method returns a QueryLocator.Id. and 50 Visualforce cursors open at the same time. For example.AssertEquals( database. Actual execution may be delayed based on service availability. consider API bulk updates. You cannot use the getContent and getContentAsPDF PageReference methods in a batch job. For more information about the AsyncApexJob object. you cannot call the Database.000 AsyncApexJob records. or WSDL method. and all cases where more than one record can be updated at a time. you must make certain that the batch job is finished before testing against the results. When a batch Apex job is run.Batch Apex Using Batch Apex • Only one batch Apex job's start method can run at a time in an organization. • • • • • • • • • • • • • • • See Also: Exception Statements Understanding Execution Governors and Limits Understanding Sharing 185 . Each method execution uses the standard governor limits anonymous block. You must be able to guarantee that the trigger will not add more batch jobs than the five that are allowed. number of errors. For a sharing recalculation. see AsyncApexJob in the Object Reference for Salesforce and Force. Salesforce only places the job in the queue at the scheduled time. you can test only one execution of the execute method. When querying for all AsyncApexJob records. The version used is the version of the running batch class that starts another batch job. Methods declared as future can't be called from a batch Apex class. Starting with Apex saved using Salesforce.executeBatch method from within any batch Apex method. Otherwise. Visualforce controller. Use the Test methods startTest and stopTest around the executeBatch method to ensure it finishes before continuing your test. email notifications are sent either to the user who submitted the batch job.com. see AsyncApexJob in the Object Reference for Salesforce and Force. you can call Database. mass record changes through the user interface. import wizards. Otherwise. When you call Database. You should run the batch job again to correct any errors. the Salesforce. In particular. Methods declared as future aren't allowed in classes that implement the Database. Batch Apex Best Practices • Use extreme care if you are planning to invoke a batch job from a trigger. Use Database.com API version of the helper class doesn’t matter. if the code is included in a managed package and the subscribing organization is running the batch job. In the event of a catastrophic failure such as a service outage. This means that when you test batch Apex.com API version 25. For more information about the AsyncApexJob object. When testing your batch Apex. All methods in the class must be defined as global or public. we recommend that the execute method delete and then re-create all Apex managed sharing for the records in the batch. any operations in progress are marked as Failed. Note that this limit doesn’t cause any batch job to fail and execute methods of batch Apex jobs still run in parallel if more than one job is running.executeBatch from the finish method only.Batchable interface. For a batch Apex class saved using Salesforce. the query will return one more record for every 10. Apex creates one additional AsyncApexJob record of type BatchApexWorker for internal use. Batch jobs that haven’t started yet remain in the queue until they're started. the email is sent to the recipient listed in the Apex Exception Notification Recipient field. If the finish method in the running batch class calls a method in a helper class to start the batch job. Each batch Apex invocation creates an AsyncApexJob record.000 AsyncApexJob records.com.0 and earlier. we recommend that you filter out records of type BatchApexWorker using the JobType field. You can use the scope parameter of the executeBatch method to limit the number of records passed into the execute method to ensure that you aren't running into governor limits. all member variables are reset to their initial state at the start of each transaction. The executeBatch method starts an asynchronous process. For each 10.com API version 26. progress. and submitter.0.executeBatch.Stateful with the class definition if you want to share instance member variables or data across job transactions. This ensures the sharing is accurate and complete. or. Use the ID of this record to construct a SOQL query to retrieve the job’s status. share. similar to an access control list (ACL) found in other platforms. Sharing rules cannot be added to a package and cannot be used to support sharing logic for apps installed from Force. Administrators first set an object’s organization-wide default sharing access level. You can’t use Apex to create criteria-based sharing rules.com AppExchange. Most sharing for a record is maintained in a related sharing object. transfer. Opportunity and Case). Sharing access can be granted using the Salesforce user interface and Force. Understanding Sharing Sharing enables record-level access control for all custom objects. Contact. though this behavior can be disabled for specific custom objects. users above a record owner in the role hierarchy are also implicitly granted Full Access to the record. The record owner is automatically granted Full Access. Sharing Rules Sharing rules are used by administrators to automatically grant users within a given group or role access to records owned by a specific group of users. Consequently. Sharing rules can be based on record ownership or other criteria.com.com managed sharing cannot be altered directly using the Salesforce user interface. Also. and manual sharing. or programmatically using Apex.com managed sharing involves sharing access granted by Force. Role Hierarchy The role hierarchy enables users above another user in the hierarchy to have the same level of access to records owned by or shared with users below. All implicit sharing added by Force. and sharing rules: Record Ownership Each record is owned by a user or optionally a queue for custom objects. and then grant additional access based on record ownership. This section provides an overview of sharing using Apex: • • • Understanding Sharing Sharing a Record Using Apex Recalculating Apex Managed Sharing For more information on sharing. 186 . For more information. as well as many standard objects (such as Account. or Apex. allowing them to view. cases and leads. criteria-based sharing cannot be tested using Apex. Developers can then use Apex managed sharing to grant additional access programmatically with Apex. Types of Sharing Salesforce has the following types of sharing: Force. the role hierarchy.com based on record ownership. Instead.Batch Apex Understanding Apex Managed Sharing Understanding Apex Managed Sharing Sharing is the act of granting a user or group of users permission to perform a set of actions on a record or set of records. The role hierarchy is not maintained with sharing records. and delete the record. the role hierarchy.com Managed Sharing Force. sharing rules. role hierarchy access is derived at runtime. see “Setting Your Organization-Wide Sharing Defaults” in the Salesforce online help. edit. SOAP API. see “Controlling Access Using Hierarchies” in the Salesforce online help. Only users with “Modify All Data” permission can add or change Apex managed sharing on a record. Only the record owner and users above the owner in the role hierarchy are granted Full Access to the record.com Managed Sharing Reason Field Value rowCause Value (Used in Apex or the Force. and the related rowCause value. Users with the “Modify All” object-level permission for the given object or the “Modify All Data” permission can also manually share a record.com managed sharing. This type of sharing is similar to Force. also known as Manual Sharing User managed sharing allows the record owner or any user with Full Access to a record to share the record with a user or group of users. The Sharing Reason Field In the Salesforce user interface. This is generally done by an end-user. Note: Apex sharing reasons and Apex managed sharing recalculation are only available for custom objects. Apex managed sharing is maintained across record owner changes. Apex Managed Sharing Apex managed sharing provides developers with the ability to support an application’s particular sharing requirements programmatically through Apex or the SOAP API. the Reason field on a custom object specifies the type of sharing used for a record.com API) ImplicitChild ImplicitParent Owner Team Rule TerritoryRule Account Sharing Associated record owner or sharing Owner Opportunity Team Sharing Rule Territory Assignment Rule • User Managed Sharing Reason Field Value rowCause Value (Used in Apex or the Force. The tables show Reason field value. It is not possible to grant other users Full Access. Each of the following list items is a type of sharing used for records. for a single record.Batch Apex Understanding Sharing User Managed Sharing. • Force. User managed sharing is removed when the record owner changes or when the access granted in the sharing does not grant additional access beyond the object's organization-wide sharing default access level. This field is called rowCause in Apex or the Force.com API) Manual TerritoryManual Manual Sharing Territory Manual • Apex Managed Sharing 187 .com API. transfer. The specified user or group can view the record only.com managed sharing. share. This access level only applies to the AccountShare object. The specified user or group can view. The detail record’s access is determined by the master’s sharing object and the relationship’s sharing setting. all custom object sharing objects are named as follows. Every share object has the following properties: 188 . “View All Data. The specified user or group can view and edit the record. the most permissive level of access is used. and delete the record. where MyCustomObject is the name of the custom object: MyCustomObject__Share Objects on the detail side of a master-detail relationship do not have an associated sharing object. Sharing granted to users implicitly through organization-wide defaults. edit. Access Levels When determining a user’s access to a record. Read Only Read/Write Full Access Read Edit All Sharing a Record Using Apex To access sharing programmatically. you must use the share object associated with the standard or custom object for which you want to share. In addition. Most share objects support the following access levels: Access Level Private API Name None Description Only the record owner and users above the record owner in the role hierarchy can view and edit the record. the role hierarchy.Batch Apex Sharing a Record Using Apex Reason Field Value rowCause Value (Used in Apex or the Force. Note: This access level can only be granted with Force. ContactShare is the sharing object for the Contact object.com API) Defined by developer Defined by developer The displayed reason for Apex managed sharing is defined by the developer. A share object includes records supporting all three types of sharing: Force. AccountShare is the sharing object for the Account object. and Apex managed sharing. and permissions such as the “View All” and “Modify All” permissions for the given object.com managed sharing. see “Custom Object Security” in the Salesforce online help. For example. user managed sharing.” and “Modify All Data” are not tracked with this object. and so on. For more information. Job__Share jobShr = new Job__Share(). ParentID RowCause The ID of the object.Batch Apex Sharing a Record Using Apex Property Name objectNameAccessLevel Description The level of access that the specified user or group has been granted for a share sObject.com.RowCause. see User and Group in the Object Reference for Salesforce and Force.AccessLevel = 'Read'. Valid values are: • Edit • Read • All Note: The All access level can only be used by Force. This field cannot be updated. For example. the property name for LeadShare object is LeadShareAccessLevel. It also includes a test method that validates this method. the sharing is automatically deleted. jobShr.com managed sharing. // This line can be omitted as 'manual' is the default value for sharing objects. This field cannot be updated.false). jobShr. The following example class contains a method that shares the job specified by the job ID with the specified user or group ID with read access.ParentId = recordId. For more information. Database. // Set the access level. or territory. jobShr. // Set the ID of user or group being granted access. The user or group IDs to which you are granting access.Job__Share. which controls who can alter the sharing record. // Set rowCause to 'manual' for manual sharing. Before you save this example class. see Access Levels on page 188. For more information about the types of users and groups you can share an object with. If the owner of the record changes. jobShr.insert(jobShr. The name of the property is AccessLevel appended to the object name.RowCause = Schema.SaveResult sr = Database. UserOrGroupId You can share a standard or custom object with users or groups.Manual.UserOrGroupId = userOrGroupId. role. A group can be a public group. // Set the ID of record being shared. public class JobSharing { static boolean manualShareRead(Id recordId. This field cannot be updated. Id userOrGroupId){ // Create new sharing object for the custom object Job. create a custom object called Job. This field must be set to an access level that is higher than the organization’s default access level for the parent object. The reason determines the type of sharing. Creating User Managed Sharing Using Apex It is possible to manually share a record to a user or a group using Apex or the SOAP API. // Insert the sharing record and capture the save result. 189 . The reason why the user or group is being granted access. // The false parameter allows for partial processing if multiple records passed // into the operation. Job__c j = new Job__c(). if(err. System. 'Manual'). } } } // Test for the manualShareRead method static testMethod void testManualShareRead(){ // Select users for the test. user2Id).getStatusCode() == StatusCode. // Test invalid job Id. if(sr.assertEquals(manualShareRead(j. // Query job sharing records.getErrors()[0]. return false.FIELD_FILTER_VALIDATION_EXCEPTION err. } } && 190 . System. j. System. 'Set the object\'s sharing model to Private.OwnerId = user1Id. insert j. user2Id).assertEquals(jShrs[0]. } else{ // Indicates failure.Name = 'Test Job'. UserOrGroupId. // Test for only one manual share on job.size().Id. Database. List<Job__Share> jShrs = [SELECT Id. 1. // Access levels equal or more permissive than the object's default // access level are not allowed. // Insert manual share for deleted job id.getMessage(). delete j.Id.UserOrGroupId. // Check if the error is related to trival access level.contains('AccessLevel')){ // Indicates success.Id.Id.Id AND UserOrGroupId= :user2Id]. false). System. List<User> users = [SELECT Id FROM User WHERE IsActive = true LIMIT 2].isSuccess()){ // Indicates success return true. 'Read'). j.assertEquals(manualShareRead(j. true). System.assertEquals(jShrs[0].assertEquals(jShrs[0]. } else { // Get first save result error. System. Id User1Id = users[0]. user2Id). // Create new job.Batch Apex Sharing a Record Using Apex // Process the save results. // Insert manual share for user who is not record owner. Id User2Id = users[1]. return true. AccessLevel.RowCause.AccessLevel.assertEquals(jShrs.').Error err = sr. // Test attributes of manual share. RowCause FROM job__share WHERE ParentId = :j. // These sharing records are not required and thus an insert exception is acceptable. • All Apex sharing reason names have the following format: MyReasonName__c Apex sharing reasons can be referenced programmatically as follows: Schema. The label is also enabled for translation through the Translation Workbench. Select the custom object. Click New in the Apex Sharing Reasons related list. This allows users and administrators to understand the source of the sharing. Click Your Name > Setup > Create > Objects. 4. This name can contain only underscores and alphanumeric characters. The label is also enabled for translation through the Translation Workbench.SharingReason__c For example. not include spaces. The label displays in the Reason column when viewing the sharing for a record in the user interface. Each Apex sharing reason has a label and a name: • The label displays in the Reason column when viewing the sharing for a record in the user interface. and must be unique in your organization. The name is used when referencing the reason in the API and Apex. To create an Apex sharing reason: 1. They also enable developers to share with the same user or group multiple times using different reasons.CustomObject__Share. see Schema Methods on page 340. and not contain two consecutive underscores.Recruiter__c For more information.com managed sharing. Apex managed sharing must use an Apex sharing reason. 2. see Access Levels on page 188. This type of sharing is similar to Force. Note: Apex sharing reasons and Apex managed sharing recalculation are only available for custom objects.rowCause. The name is used when referencing the reason in the API and Apex.rowCause. Apex sharing reasons are a way for developers to track why they shared a record with a user or group of users. Using multiple Apex sharing reasons simplifies the coding required to make updates and deletions of sharing records. an Apex sharing reason called Recruiter for an object called Job can be referenced as follows: Schema. this is Public Read/Write. 3. Apex managed sharing is maintained across record owner changes. 191 . not end with an underscore. Enter a name for the Apex sharing reason. Click Save. 6. Enter a label for the Apex sharing reason. For more information. Apex sharing reasons are defined on an object's detail page.Job__Share. Only users with “Modify All Data” permission can add or change Apex managed sharing on a record. Creating Apex Managed Sharing Apex managed sharing enables developers to programmatically manipulate sharing to support their application’s behavior through Apex or the SOAP API. 5. For custom objects. It must begin with a letter.Batch Apex Sharing a Record Using Apex Important: The object’s organization-wide default access level must not be set to the most permissive access level. trigger JobApexSharing on Job__c (after insert) { if(trigger. // Set the Apex sharing reason for hiring manager and recruiter recruiterShr. Also. // Set the ID of user or group being granted access recruiterShr. // Check if the error is related to a trivial access level // Access levels equal or more permissive than the object's default // access level are not allowed.Job__Share. // Create counter Integer i=0.FIELD_FILTER_VALIDATION_EXCEPTION 192 . This example requires a custom object called Job.ParentId = job. jobShrs.ParentId = job.Id.Recruiter__c. hmShr.RowCause. // Process the save results for(Database. with two lookup fields associated with User records called Hiring_Manager and Recruiter.Hiring_Manager__c. hmShr = new Job__Share().getErrors()[0].Job__Share. the Job custom object should have two sharing reasons added called Hiring_Manager and Recruiter. // Add objects to list for insert jobShrs.getStatusCode() == StatusCode.SaveResult sr : lsr){ if(!sr.Batch Apex Sharing a Record Using Apex Apex Managed Sharing Example For this example. // Declare variables for recruiting and hiring manager sharing Job__Share recruiterShr.UserOrGroupId = job. // Set the ID of record being shared recruiterShr.insert(jobShrs. } // Insert sharing records and capture save result // The false parameter allows for partial processing if multiple records are passed // into the operation Database.RowCause = Schema.UserOrGroupId = job. for(Job__c job : trigger.isInsert){ // Create a new list of sharing objects for Job List<Job__Share> jobShrs = new List<Job__Share>(). Job__Share hmShr.add(recruiterShr).Id. // These sharing records are not required and thus an insert exception is // acceptable.isSuccess()){ // Get the first save result error Database.AccessLevel = 'edit'. You want to validate that the recruiter and hiring manager listed on the job have access to the record. hmShr.false). hmShr.Hiring_Manager__c.AccessLevel = 'read'.Error err = sr.add(hmShr). if(!(err.Recruiter__c. The following trigger grants the recruiter and hiring manager access when the job record is created.new){ // Instantiate the sharing objects recruiterShr = new Job__Share().RowCause.SaveResult[] lsr = Database. // Set the access level recruiterShr.RowCause = Schema. suppose you are building a recruiting application and have an object called Job. hmShr. You can execute this class from the custom object detail page where the Apex sharing reason is specified.getMessage(). this is Public Read/Write. trigger. on the custom object's detail page.com managed sharing when appropriate. see “Monitoring the Apex Job Queue” in the Salesforce online help. you must write an Apex class that implements a Salesforce-provided interface to do the recalculation. is deleted when the object’s sharing model changes from Private to Public Read Only. the original share rows are updated to Write. The recalculation adds Force. and so on). If users can access an account because they can access its child records (contact. Recalculating Apex Managed Sharing Salesforce automatically recalculates sharing for all records on an object when its organization-wide sharing default access level changes. For example. Note: Every time a custom object's organization-wide sharing default access level is updated. Note: Apex sharing reasons and Apex managed sharing recalculation are only available for custom objects. In addition. } } i++.Batch Apex Recalculating Apex Managed Sharing && err. click Your Name > Setup > Monitoring > Apex Jobs. To monitor or stop the execution of the Apex recalculation. all types of sharing are removed if the access they grant is considered redundant. opportunity. addError( 'Unable to grant sharing access due to following exception: ' + err. You can also use the Database. } } } Under certain circumstances. manual sharing. Consider these examples: • • If a manual share access level is set to Read and you insert a new one that’s set to Write. For custom objects.getMessage()). inserting a share row results in an update of an existing share row. the row cause of the parent implicit share is replaced by the sharing rule row cause. and an account sharing rule is created.get(jobShrs[i]. indicating the higher level of access. For more information. Important: The object’s organization-wide default access level must not be set to the most permissive access level. To recalculate Apex managed sharing. any Apex recalculation classes defined for associated custom object are also executed. which grants Read Only access to a user.ParentId). You must then associate the class with the custom object.executeBatch method to programmatically invoke an Apex managed sharing recalculation. case.newMap. For more information. see Access Levels on page 188. in the Apex Sharing Recalculation related list. An administrator might need to recalculate the Apex managed sharing for an object if a locking issue prevented Apex code from granting access to a user as defined by the application’s logic. 193 . indicating the higher level of access.contains('AccessLevel'))){ // Throw an error when the error is not related to trivial access level. // Replace its value with a valid email address. List<sObject> scope){ // Create a map for the chunk of records passed into method. global Database. global class JobSharingRecalc implements Database. this is Public Read/Write. // Set the ID of user (hiring manager) on the Job record being granted access. // Construct new sharing records for the hiring manager and recruiter // on each Job record. Job__c> jobMap = new Map<ID. The following Apex class performs this validation.QueryLocator start(Database. including recalculating Apex managed sharing.rowCause.BatchableContext BC){ return Database. Apex Managed Sharing Recalculation Example For this example. // Only records using an Apex sharing reason for this app should be returned.Job__Share. Map<ID.Batch Apex Recalculating Apex Managed Sharing Creating an Apex Class for Recalculating Sharing To recalculate Apex managed sharing. For more information. Important: The object’s organization-wide default access level must not be set to the most permissive access level.Hiring_Manager__c.rowCause. see Access Levels on page 188.Hiring_Manager__c)].Batchable<sObject> { // String to hold email address that emails will be sent to. For custom objects. // This method returns a SOQL query locator containing the records // to be recalculated. Job__c>((List<Job__c>)scope).getQueryLocator([SELECT Id. } // The executeBatch method is called for each chunk of records returned from start.Batchable interface is used for all batch Apex processes. 194 . also consider the best practices. This class must implement the Salesforce-provided interface Database. Before creating an Apex managed sharing recalculation class. Also.BatchableContext BC. jobHMShr.Job__Share.Recruiter__c OR RowCause = :Schema. You can implement this interface more than once in your organization.com'. Hiring_Manager__c. the Job custom object should have two sharing reasons added called Hiring_Manager and Recruiter. You want to validate that the recruiter and hiring manager listed on the job have access to the record. The Database. This example requires a custom object called Job. you must write an Apex class to do the recalculation.UserOrGroupId = job. static String emailAddress = 'admin@yourcompany. // Create a list of Job__Share objects to be inserted. see Using Batch Apex on page 177. replace the email address with a valid email address that you want to to send error notifications and job completion notifications to. List<Job__Share> oldJobShrs = [SELECT Id FROM Job__Share WHERE Id IN :jobMap. For more information on the methods that must be implemented. Recruiter__c FROM Job__c]). for(Job__c job : jobMap. List<Job__Share> newJobShrs = new List<Job__Share>(). // The start method is called at the beginning of a sharing recalculation. // The hiring manager on the job should always have 'Read Only' access. // Locate all existing sharing records for the Job records in the batch. global void execute(Database. suppose you are building a recruiting application and have an object called Job.keySet() AND (RowCause = :Schema.values()){ Job__Share jobHMShr = new Job__Share(). Before you run this sample.Batchable. Job__Share jobRecShr = new Job__Share(). with two lookup fields associated with User records called Hiring_Manager and Recruiter. String[] toAddresses = new String[] {emailAddress}.SaveResult[] lsr = Database.insert(newJobShrs.setToAddresses(toAddresses).SingleEmailMessage().Batch Apex Recalculating Apex Managed Sharing jobHMShr.AccessLevel = 'Edit'. // Set the rowCause to the Apex sharing reason for recruiter. // The false parameter allows for partial processing if multiple records are // passed into operation. // The recruiter on the job should always have 'Read/Write' access.RowCause. mail.setSubject('Apex Sharing Recalculation Exception'). Messaging.UserOrGroupId = job. Database. // The ID of the record being shared jobRecShr. // Process the save results for insert.SingleEmailMessage mail = new Messaging.Job__Share. // These sharing records are not required and thus an insert exception // is acceptable.Recruiter__c.RowCause = Schema.Id.add(jobHMShr). for(Database. // Set the rowCause to the Apex sharing reason for hiring manager. // This allows new sharing records to be written from scratch.ParentId = job.RowCause.contains('AccessLevel'))){ // Error is not related to trivial access level.SaveResult sr : lsr){ if(!sr. } try { // Delete the existing sharing records.Recruiter__c. // Add sharing record to list for insertion.getErrors()[0]. // Set the ID of user (recruiter) on the Job record being granted access.AccessLevel = 'Read'. // Insert the new sharing records and capture the save result. // Check if the error is related to trivial access level. jobRecShr. jobHMShr.getMessage()).SingleEmailMessage[] { mail }).Job__Share. // Send an email to the Apex job's submitter.FIELD_FILTER_VALIDATION_EXCEPTION && err. jobRecShr. jobRecShr. Database. // The ID of the record being shared jobHMShr.Id. mail.false). // Add the sharing record to the list for insertion.add(jobRecShr).RowCause = Schema. Delete oldJobShrs.setPlainTextBody( 'The Apex sharing recalculation threw the following exception: ' + err. newJobShrs. mail. if(!(err. // This establishes the sharing record as Apex managed sharing. } } } 195 .ParentId = job. newJobShrs.Error err = sr.getMessage().isSuccess()){ // Get the first save result error. // Access levels equal or more permissive than the object's default // access level are not allowed.getStatusCode() == StatusCode. // This establishes the sharing record as Apex managed sharing. Messaging.Hiring_Manager__c.sendEmail(new Messaging. Hiring_Manager__c = User2Id.SingleEmailMessage[] { mail }).SingleEmailMessage mail = new Messaging. String[] toAddresses = new String[] {emailAddress}. } } // The finish method is called at the end of a sharing recalculation. the Job custom object should have two sharing reasons added called Hiring_Manager and Recruiter. // Select users for the test.SingleEmailMessage().setPlainTextBody ('The Apex sharing recalculation finished processing'). mail. mail. List<User> users = [SELECT Id FROM User WHERE IsActive = true LIMIT 2]. ID User1Id = users[0].Name = 'Test Job ' + i.setToAddresses(toAddresses). j. mail.Id. 196 . j. String jobId = Database. ID User2Id = users[1]. mail. This example requires a custom object called Job.sendEmail(new Messaging.Batch Apex Recalculating Apex Managed Sharing } catch(DmlException e) { // Send an email to the Apex job's submitter on failure.setToAddresses(toAddresses). } } Testing Apex Managed Sharing Recalculations This example inserts five Job records and invokes the batch job that is implemented in the batch class of the previous example. Note that since email messages aren’t sent from tests.i<5. Before you run this test. set the organization-wide default sharing for Job to Private.setPlainTextBody( 'The Apex sharing recalculation threw the following exception: ' + e. Messaging. // Invoke the Batch class. JobSharingRecalc recalc = new JobSharingRecalc(). and because the batch class is invoked by a test method.SingleEmailMessage[] { mail }).').setSubject('Apex Sharing Recalculation Exception'). Messaging.setSubject('Apex Sharing Recalculation Completed. } insert testJobs.SingleEmailMessage(). Test.sendEmail(new Messaging. Also.stopTest(). List<Job__c> testJobs = new List<Job__c>(). Test. with two lookup fields associated with User records called Hiring_Manager and Recruiter. @isTest private class JobSharingTester { // Test for the JobSharingRecalc class static testMethod void testApexSharing(){ // Instantiate the class implementing the Database. j.executeBatch(recalc).add(j). mail.startTest().getMessage()). for (Integer i=0.Recruiter__c = User1Id. String[] toAddresses = new String[] {emailAddress}.BatchableContext BC){ // Send an email to the Apex job's submitter notifying of job completion. // Insert some test job records.Id.i++) { Job__c j = new Job__c(). testJobs. Messaging.Batchable interface. mail. Messaging. global void finish(Database.SingleEmailMessage mail = new Messaging. the email notifications won’t be sent in this case. rowCause. You cannot associate the same Apex class multiple times with the same custom object.Job__Share.NumberOfErrors).assertEquals(jobShr. Status. System. Choose the Apex class that recalculates the Apex sharing for this object.Recruiter__c){ System. (SELECT Id. AccessLevel. To associate an Apex managed sharing recalculation class with a custom object: 1. RowCause FROM Shares WHERE (RowCause = :Schema.RowCause.'Edit'). ParentId.rowCause.Shares){ // Test the sharing record for hiring manager on job. for(Job__Share jobShr : job.size() == 2).job.UserOrGroupId.Recruiter__c).RowCause == Schema.assertEquals(jobShr. System. CreatedDate. List<Job__c> jobs = [SELECT Id.RowCause == Schema. Hiring_Manager__c. 3.UserOrGroupId.Hiring_Manager__c)) FROM Job__c]. if(jobShr.assertEquals(jobShr.Recruiter__c OR RowCause = :Schema.Job__Share.assertEquals(0. for(Job__c job : jobs){ // Two Apex managed sharing records should exist for each job // when using the Private org-wide default.RowCause. 197 .Hiring_Manager__c).Hiring_Manager__c){ System. 4.'Read'). System. The class you choose must implement the Database.Batchable interface. aaj. // This query returns jobs and related sharing records that were inserted // by the batch job's execute method. AsyncApexJob aaj = [Select JobType. Click Your Name > Setup > Create > Objects. else if(jobShr.Job__Share.AccessLevel.assertEquals(jobShr. UserOrGroupId. 5.Batch Apex Recalculating Apex Managed Sharing // Get the Apex job and verify there are no errors.Shares. Select the custom object. } } } } } Associating an Apex Class Used for Recalculation An Apex class used for recalculation must be associated with a custom object. 2. System. } // Test the sharing record for recruiter on job. Click Save. TotalJobItems.AccessLevel.Job__Share. JobItemsProcessed. Click New in the Apex Sharing Recalculations related list.job. CompletedDate. NumberOfErrors from AsyncApexJob where Id = :jobId]. // Validate that Apex managed sharing exists on jobs. Recruiter__c.assert(job. This chapter covers the following: • • • • Understanding the Debug Log Handling Uncaught Exceptions Understanding Execution Governors and Limits Using Governor Limit Email Warnings 198 . To further aid debugging.. Last but not least. Apex enforces a certain set of governor limits for your running code to ensure shared resources aren’t monopolized in a multi-tenant environment. • • • • Understanding the Debug Log Handling Uncaught Exceptions Understanding Execution Governors and Limits Using Governor Limit Email Warnings Apex provides debugging support. you can select to have emails sent to end-users who are running code that surpasses a certain percentage of any governor limit.Chapter 8 Debugging Apex In this chapter . You can debug your Apex code using the Developer Console and debug logs. Apex sends emails to developers for unhandled exceptions.. Furthermore. After a user reaches this limit. the oldest debug logs start being overwritten.0 APEX_CODE.0. You can retain and manage the debug logs for specific users. For example: The following is an example of a header: 25.DEBUG. The system generates a debug log for a user every time that user executes a transaction that is included in the filter criteria.APEX_PROFILING. and errors that occur when executing a transaction or while running unit tests. • • Inspecting the Debug Log Sections After you generate a debug log. click Your Name > Setup > Monitoring > Debug Logs. the API version is 25.INFO. Any existing logs are not overwritten.INFO In this example. Click Reset on the Monitoring Debug logs page to reset the number of logs for that user back to 20.CALLOUT. that user can record up to 20 debug logs. Debug logs that are larger than 2 MB in size are truncated.VALIDATION. Once your organization has reached 50 MB of debug logs. the type and amount of information listed depends on the filter values you set for the user. To view saved debug logs. WORKFLOW. system processes.SYSTEM. The following are the limits for debug logs: • Once a user is added.INFO. A debug log has the following sections: Header The header contains the following information: • The version of the API used during the transaction.INFO. and the following debug log categories and levels have been set: Apex Code Apex Profiling Callout Database System Validation Visualforce Workflow DEBUG INFO INFO INFO DEBUG INFO INFO INFO 199 .VISUALFORCE. However. the format for a debug log is always the same.DEBUG.Debugging Apex Understanding the Debug Log Understanding the Debug Log A debug log records database operations. debug logs stop being recorded for that user. • The log category and level used to generate the log.INFO.INFO. Each organization can retain up to 50 MB of debug logs. Each debug log can only be 2 MB.DB. The trigger ends CODE_UNIT_FINISHED <-. Code Units A code unit is a discrete unit of work within a transaction. Units of work can embed other units of work. but are not limited to. For example. The execution is delimited by EXECUTION_STARTED and EXECUTION_FINISHED. Note: A class is not a discrete unit of code. or messages being specifically written to the debug log. as well as each execution of the execute method • Execution of the Apex System. as is a webService method.Debugging Apex Understanding the Debug Log Execution Units An execution unit is equivalent to a transaction. For example: EXECUTION_STARTED CODE_UNIT_STARTED|[EXTERNAL]execute_anonymous_apex CODE_UNIT_STARTED|[EXTERNAL]MyTrigger on Account trigger event BeforeInsert for [new] CODE_UNIT_FINISHED <-. For example: Figure 5: Debug Log Line Example 200 .Schedule execute method • Incoming email handling Log Lines Included inside the units of code. These indicate what code or rules are being executed.The executeAnonymous ends EXECUTION_FINISHED Units of code include. It contains everything that occurred within the transaction. Units of code are indicated by CODE_UNIT_STARTED and CODE_UNIT_FINISHED. or a validation rule. the following: • Triggers • Workflow invocations and time-based workflow • Validation rules • Approval processes • Apex lead convert • @future method invocations • Web service invocations • executeAnonymous calls • Visualforce property accesses on Apex controllers • Visualforce actions on Apex controllers • Execution of the batch Apex start and finish methods. a trigger is one unit of code. Contains information about the most expensive queries (that used the most resources).030 (30064000)|EXECUTION_STARTED 11:47:46.038 BeforeUpdate 11:47:47. • event identifier: consists of the specific event that triggered the debug log being written to. The following is an example debug log: 22.INFO.INFO. and Apex lead convert. you can raise the log verbosity for a given class while turning off logging for other classes or triggers within a single request. such as SAVEPOINT_RESET or VALIDATION_RULE.038 (38296000)|SYSTEM_METHOD_ENTRY|[2]|System. The time is in the user's time zone and in the format HH:mm:ss. WORKFLOW.030 (30159000)|CODE_UNIT_STARTED|[EXTERNAL]|TRIGGERS 11:47:46.0 APEX_CODE.debug(ANY) 11:47:46. the log contains the following information: • Cumulative resource usage—Logged at the end of many code units. delimited by a pipe (|).546 (38587000)|CUMULATIVE_LIMIT_USAGE 11:47:46.debug(ANY) 11:47:46.DEBUG.DB. executeAnonymous. 201 .038 (38450000)|USER_DEBUG|[2]|DEBUG|Hello World! 11:47:46. The elapsed time value is excluded from logs reviewed in the Developer Console. Apex web service methods.VALIDATION. The value represents the time elapsed in nanoseconds since the start of the request.Debugging Apex Understanding the Debug Log Log lines are made up of a set of fields. and so on.DEBUG.546|CUMULATIVE_LIMIT_USAGE_END 11:47:46. Additional Log Data In addition. such as the method name or the line and character number where the code was executed. Apex test methods. @future methods.VISUALFORCE. to evaluate the output of a complex process.INFO. and any additional information logged with that event. The format is: • timestamp: consists of the time when the event occurred and a value between parentheses. DML invocations.154 (38715000)|CODE_UNIT_FINISHED|myAccountTrigger on Account trigger event for [001D000000IzMaE] (1154831000)|CODE_UNIT_FINISHED|TRIGGERS (1154881000)|EXECUTION_FINISHED Setting Debug Log Filters for Apex Classes and Triggers Debug log filtering provides a mechanism for fine-tuning the log verbosity at the trigger and class level.030 (30271000)|CODE_UNIT_STARTED|[EXTERNAL]|01qD00000004JvP|myAccountTrigger on Account trigger event BeforeUpdate for [001D000000IzMaE] 11:47:46.SYSTEM.546|LIMIT_USAGE_FOR_NS|(default)| Number of SOQL queries: 0 out of 100 Number of query rows: 0 out of 50000 Number of SOSL queries: 0 out of 20 Number of DML statements: 0 out of 150 Number of DML rows: 0 out of 10000 Number of code statements: 1 out of 200000 Maximum heap size: 0 out of 6000000 Number of callouts: 0 out of 10 Number of Email Invocations: 0 out of 10 Number of fields describes: 0 out of 100 Number of record type describes: 0 out of 100 Number of child relationships describes: 0 out of 100 Number of picklist describes: 0 out of 100 Number of future calls: 0 out of 10 11:47:46.SSS. For example. batch Apex message processing.CALLOUT. such as triggers. • Cumulative profiling information—Logged once at the end of the transaction.038 (38520000)|SYSTEM_METHOD_EXIT|[2]|System. This is especially helpful when debugging Apex logic.154 11:47:47.INFO 11:47:46.INFO.INFO.APEX_PROFILING. the debug log levels of Class1 are raised to the finest granularity.doSomething(). 1. unless they have these settings overridden. Class2 isn't in the code path that causes a problem. For example: public class Class2 { public static void anotherMethod() { // Some code that causes Trigger2 to be fired. For example: public class Class1 { public static void someMethod() { Class3. which in turn calls a method of a utility class. All class methods and triggers in the execution path inherit the debug log settings from their caller.thirdMethod(). suppose Class1 is causing some issues that you would like to take a closer look at. } } public class Class3 { public static void thirdMethod() { UtilityClass. } } 202 . these debug levels also apply to the class methods that your class or trigger calls and the triggers that get executed as a result. to be executed. } 2. Class3 doesn't override these log levels. To this end.someMethod(). Class2. Trigger2. therefore it has its logging minimized to log only errors for the Apex Code category. For this scenario. so it has its log filters turned off. Class1 calls a method of Class3. Trigger2 inherits these log settings from Class2. The following diagram illustrates overriding debug log levels at the class and trigger level. Figure 6: Fine-tuning debug logging for classes and triggers The following is a pseudo-code example that the diagram is based on. Similarly. Class2 causes a trigger. UtilityClass has already been tested and is known to work properly. and therefore inherits the granular log filters of Class1. Trigger1 calls a method of Class1 and another method of Class2. For example: trigger Trigger1 on Account (before insert) { Class1. } } 3. However.anotherMethod().Debugging Apex Understanding the Debug Log When you override the debug log levels for a class or trigger. if you want to see debug logs from a specific user. Click Filter and type text to filter the visible logs. Click Open Raw Log to open the selected log in a plain text view that displays the unformatted contents of the debug log. To learn more about working with logs in a System Log view in the Developer Console. what triggered that operation. and debug log events. and what occurred afterward. those logs are still accessible from the Debug Log page. Click Your Name > Setup > Monitoring > Debug Logs. Click Download Log to download the selected log. Click Clear to remove all logs from the list. Logs open in a System Log view. click Log Filters. 6.Debugging Apex Working with Logs in the Developer Console To set log filters: 1. The log filters are set to the default log levels. The filter is case-sensitive. 7. and validation logic. debug log levels. workflow. 3. 4. 2. including newly-generated system logs created by other users. Click Open to open the selected log in a new System Log view. Apex processing. From a class or trigger detail page. 3. When using the Developer Console or monitoring a debug log. type that user's name. For example. Choose the log level desired for each log category. See Also: Working with Logs in the Developer Console Debugging Apex API Calls Working with Logs in the Developer Console Use the logs tab in the Developer Console to open debug logs. To learn more about debug log categories. You can use this view to inspect debug logs that include database events. 1. This button is a toggle: click the button a second time to display all logs. Click Override Log Filters. 2. Tip: If you are monitoring debug logs for a user. Select Show My Current Logs Only to display only logs generated by you since opening the Developer Console. see “System Log View” in the Salesforce online help. Deselect to see all debug logs saved for your organization. see Setting Debug Log Filters. you can specify the level of information that gets included in the log. System Log view is a context-sensitive execution viewer that shows the source of an operation. Click Auto Hide Logs to automatically hide all existing logs the next time the page is refreshed. 203 . 5. including every data manipulation language (DML) statement or inline SOQL or SOSL query. and the start and completion of any test method. WARN and ERROR levels. The amount of information logged for each category depends on the log level: Log Category Database Workflow Validation Callout Description Includes information about database activity. Includes the request-response XML that the server is sending and receiving from an external Web service. Debug Log Categories You can specify the following log categories. and so on. Note: Not all levels are available for all categories. whether the rule evaluated true or false. Specific events are logged based on the combination of category and levels. and so on. if you select FINE. Apex Code Apex Profiling Visualforce System Debug Log Levels You can specify the following log levels. such as the line and character number where the event started. fields associated with the event. and so on. such as the name of the rule. inline SOQL or SOSL queries. and so on. and so on. that is. the actions taken. Only the levels that correspond to one or more events are available. This is useful when debugging issues related to using Force. The levels are listed from lowest to highest. the number of emails sent.com Web services API calls. Includes information about Visualforce events including serialization and deserialization of the view state or the evaluation of a formula field in a Visualforce page. Includes information about validation rules. the start and completion of any triggers. the log will also include all events logged at DEBUG. Most events start being logged at the INFO level. such as information from Apex or workflow rules. Includes information for workflow rules. Includes information about Apex code and can include information such as log messages generated by DML statements. INFO.Debugging Apex Working with Logs in the Developer Console Log category The type of information logged. Includes cumulative profiling information. Log level The amount of information logged. such as the limits for your namespace. The level is cumulative. Event type The combination of log category and log level that specify which events get logged.debug method. duration of the event in milliseconds. such as the rule name. Each event can log additional information. Includes information about calls to all system methods such as the System. • • ERROR WARN 204 . the event identifier is made up of the following: • Event name: USER_DEBUG • Line number of the event in the code: [2] • Logging level the System. If the Developer Console is open. 205 . including logs created during a deployment. Debug Event Types The following is an example of what is written to the debug log. the deployment might take longer than expected. event identifier: consists of the specific event that triggered the debug log being written to. • The following is an example of a debug log line. The time is in the user's time zone and in the format HH:mm:ss.Debugging Apex Working with Logs in the Developer Console • • • • • INFO DEBUG FINE FINER FINEST Important: Before running a deployment. Figure 7: Debug Log Line Example In this example. such as SAVEPOINT_RESET or VALIDATION_RULE. the log levels in the Developer Console affect all logs. The value represents the time elapsed in nanoseconds since the start of the request. The format is timestamp | event identifier: • timestamp: consists of the time when the event occurred and a value between parentheses. and any additional information logged with that event.Debug method was set to: DEBUG • User-supplied string for the System.Debug method: Hello world! The following example of a log line is triggered by this code snippet. If the Apex Code log level is set to FINEST. verify that the Apex Code log level is not set to FINEST. The elapsed time value is excluded from logs reviewed in the Developer Console. The event is USER_DEBUG. such as the method name or the line and character number where the code was executed.SSS. the event identifier is made up of the following: • Event name: DML_BEGIN • Line number of the event in the code: [5] • DML operation type—Insert: Op:Insert • Object name: Type:Invoice_Statement__c • Number of rows passed into the DML operation: Rows:1 The following table lists the event types that are logged. as well as what combination of log level and category cause an event to be logged. request headers Line number. such as MyTrigger on Account trigger event BeforeInsert for [new] Level Logged FINEST INFO and above INFO and above ERROR and above ERROR and above Apex Code Callout Callout Apex Code Apex Code 206 .Debugging Apex Working with Logs in the Developer Console Figure 8: Debug Log Line Code Snippet The following log line is recorded when the test reaches line 5 in the code: 15:51:01. Event Name BULK_HEAP_ALLOCATE CALLOUT_REQUEST CALLOUT_RESPONSE CODE_UNIT_FINISHED CODE_UNIT_STARTED Fields or Information Logged With Event Category Logged Number of bytes allocated Line number. response body None Line number. code unit name.071 (55856000)|DML_BEGIN|[5]|Op:Insert|Type:Invoice_Statement__c|Rows:1 In this example. what fields or other information get logged with each event. message None None Exception type. number of bytes Line number. number of rows passed into DML operation Line number Line number Package namespace Line number. Apex class ID. and so on). the string <init>() with the Apex Code types of parameters.Debugging Apex Working with Logs in the Developer Console Event Name CONSTRUCTOR_ENTRY Fields or Information Logged With Event Category Logged Line number. number of bytes deallocated Line number Namespace. message. between the parentheses Apex Code Level Logged DEBUG and above CONSTRUCTOR_EXIT Line number. stack trace Line number. following limits: Number of SOQL queries Number of query rows Number of SOSL queries Number of DML statements Number of DML rows Number of code statements Maximum heap size Number of callouts Number of Email Invocations Number of fields describes DML_END EMAIL_QUEUE ENTERING_MANAGED_PKG EXCEPTION_THROWN EXECUTION_FINISHED EXECUTION_STARTED FATAL_ERROR HEAP_ALLOCATE HEAP_DEALLOCATE IDEAS_QUERY_EXECUTE LIMIT_USAGE_FOR_NS Apex Code Apex Code Apex Code Apex Code Apex Code Apex Code Apex Code Apex Code Apex Code DB Apex Profiling INFO and above INFO and above INFO and above INFO and above ERROR and above ERROR and above ERROR and above FINER and above FINER and above FINEST FINEST 207 . between the parentheses None Apex Profiling Apex Profiling Apex Profiling Apex Profiling Apex Profiling DEBUG and above CUMULATIVE_LIMIT_USAGE INFO and above INFO and above FINE and above FINE and above FINE and above INFO and above CUMULATIVE_LIMIT_USAGE_END None CUMULATIVE_PROFILING None CUMULATIVE_PROFILING_BEGIN None CUMULATIVE_PROFILING_END None DML_BEGIN Line number. operation (such as Insert. Apex Code Update. the sring <init>() with the types of parameters. if any. exception type. record name or type. if any. class name. query DB source 208 .com ID of the class System or trigger that has its log filters set and that is going into scope. the name of this class or trigger. Savepoint name Line number. the Force. the Force. the name of this class or trigger. DEBUG and above DEBUG and above POP_TRACE_FLAGS Line number.runAs() invocations Level Logged METHOD_ENTRY METHOD_EXIT Line number. new trigger Milestone ID None Case ID Workflow Workflow Workflow SLA_EVAL_MILESTONE SLA_NULL_START_DATE SLA_PROCESS_CASE SOQL_EXECUTE_BEGIN INFO and above INFO and above INFO and above INFO and above Line number. the Force. processing time. load time. Apex Code method signature Line number. the log filter settings that are now in effect after leaving this scope Line number. the Force. the log filter settings that are now in effect after entering this scope Line number.com ID of the class.com ID of the class. For constructors. Workflow number of case milestones to insert/update/delete. the following information is logged: Line number. number of aggregations. Savepoint name DB DB DB INFO and above PUSH_TRACE_FLAGS INFO and above QUERY_MORE_ITERATIONS INFO and above INFO and above INFO and above INFO and above SAVEPOINT_ROLLBACK SAVEPOINT_SET SLA_END Number of cases.com ID of the class System or trigger that has its log filters set and that is going out of scope.Debugging Apex Working with Logs in the Developer Console Event Name Fields or Information Logged With Event Category Logged Number of record type describes Number of child relationships describes Number of picklist describes Number of future calls Number of find similar calls Number of System. number of queryMore iterations Line number. Apex Code method signature. the event is logged at that level instead. logging level. if any. method signature Mode name Mode name None System System System System Apex Profiling Apex Profiling Apex Code DEBUG SYSTEM_METHOD_ENTRY SYSTEM_METHOD_EXIT SYSTEM_MODE_ENTER SYSTEM_MODE_EXIT TESTING_LIMITS DEBUG DEBUG INFO and above INFO and above INFO and above FINE and above DEBUG and above by default. VALIDATION_ERROR VALIDATION_FAIL Error message None Validation Validation INFO and above INFO and above 209 . method signature Line number. duration in milliseconds DB DB DB Apex Profiling Level Logged INFO and above INFO and above INFO and above FINE and above STACK_FRAME_VARIABLE_LIST Frame number. the string <init>() with the System types of parameters. between the parentheses SYSTEM_CONSTRUCTOR_EXIT Line number. between the parentheses Line number. duration in milliseconds Line number. number of rows. query source Line number. For example: var1:50 var2:'Hello World' STATEMENT_EXECUTE STATIC_VARIABLE_LIST Line number Apex Code FINER and above FINE and above Variable list of the form: Variable number Apex Profiling | Value. variable list of the form: Variable number | Value. number of rows. If the user sets the log level for the System. if any. user-supplied string method. For example: var1:50 var2:'Hello World' SYSTEM_CONSTRUCTOR_ENTRY Line number. the string <init>() with the System DEBUG types of parameters.Debugging Apex Working with Logs in the Developer Console Event Name SOQL_EXECUTE_END SOSL_EXECUTE_BEGIN SOSL_EXECUTE_END Fields or Information Logged With Event Category Logged Line number.Debug TOTAL_EMAIL_RECIPIENTS_QUEUED Number of emails sent USER_DEBUG Line number. rule name. rule Email template ID. type. action ID. trigger type (if rule respects trigger types) EntityName: NameField Id. method name. formula VF_EVALUATE_FORMULA_END VF_PAGE_MESSAGE None Message text VF_SERIALIZE_VIEWSTATE_BEGIN View state ID VF_SERIALIZE_VIEWSTATE_END None WF_ACTION WF_ACTION_TASK WF_ACTIONS_END WF_APPROVAL Action description Task subject. the variable's address Validation Validation Validation Apex Code Level Logged INFO and above INFO and above INFO and above FINEST VARIABLE_SCOPE_BEGIN Line number. CC emails Summary of actions enqueued Case ID. a string representation of the variable's value. owner. Workflow WF_CRITERIA_END WF_EMAIL_ALERT WF_EMAIL_SENT WF_ENQUEUE_ACTIONS WF_ESCALATION_ACTION WF_ESCALATION_RULE Boolean value indicating success (true or false) Workflow Action ID. rule. business hours None Workflow Workflow Workflow Workflow Workflow INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above 210 . a value that indicates if the variable is static None Element name. values None Rule name Line number. variable name.Debugging Apex Working with Logs in the Developer Console Event Name VALIDATION_FORMULA VALIDATION_PASS VALIDATION_RULE VARIABLE_ASSIGNMENT Fields or Information Logged With Event Category Logged Formula source. assignee template ID rule ID. EntityName: NameField Workflow Id. recipients. due date Workflow Summary of actions performed Workflow Transition type. a value Apex Code that indicates if the variable can be referenced. return type Apex Code Apex Code Visualforce Visualforce Visualforce Visualforce Apex Code Visualforce Visualforce Workflow FINEST VARIABLE_SCOPE_END VF_APEX_CALL FINEST INFO and above INFO and above INFO and above FINER and above FINER and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above VF_DESERIALIZE_VIEWSTATE_BEGIN View state ID VF_DESERIALIZE_VIEWSTATE_END None VF_EVALUATE_FORMULA_BEGIN View state ID. variable name. process node name EntityName: NameField Id EntityName: NameField Id WF_APPROVAL_REMOVE WF_APPROVAL_SUBMIT WF_ASSIGN WF_CRITERIA_BEGIN Workflow Workflow Workflow Owner. email template ID. next owner type. Boolean value indicating result (true or false) EntityName: NameField Id. owner Workflow Workflow Workflow Workflow Workflow Workflow Workflow Workflow Workflow Workflow Workflow Workflow Notifier name. indicating order Rule type None Value Filter criteria EntityName: NameField Id None Process name Node type time action container. values None Owner. time action. evaluation Datetime EntityName: NameField Id. Workflow 211 . notifier template ID Integer. Workflow WF_PROCESS_NODE WF_REASSIGN_RECORD WF_RESPONSE_NOTIFY WF_RULE_ENTRY_ORDER WF_RULE_EVAL_BEGIN WF_RULE_EVAL_END WF_RULE_EVAL_VALUE WF_RULE_FILTER WF_RULE_INVOCATION WF_RULE_NOT_EVALUATED WF_SOFT_REJECT WF_SPOOL_ACTION_BEGIN WF_TIME_TRIGGER Process name EntityName: NameField Id. field None rule EntityName: NameField Id. notifier email. object or Level Logged INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above INFO and above Workflow Workflow Workflow Workflow Workflow Workflow field name WF_FORMULA WF_HARD_REJECT WF_NEXT_APPROVER WF_NO_PROCESS_FOUND WF_OUTBOUND_MSG Formula source.Debugging Apex Working with Logs in the Developer Console Event Name WF_EVAL_ENTRY_CRITERIA WF_FIELD_UPDATE Fields or Information Logged With Event Category Logged Process name. action ID. 212 . Only the Apex_code LogCategory uses the log category levels.Debugging Apex Debugging Apex API Calls Event Name WF_TIME_TRIGGERS_BEGIN Fields or Information Logged With Event Category Logged None Workflow Level Logged INFO and above See Also: Understanding the Debug Log Debugging Apex API Calls Debugging Apex API Calls All API calls that invoke Apex support a debug facility that allows access to detailed information about the execution of the code. In addition to the Developer Console. Element Name LogCategory Type string Description Specify the type of information returned in the debug log. the following log levels are still supported as part of the DebuggingHeader for backwards compatibility. Valid log levels are (listed from lowest to highest): • • • • • • • ERROR WARN INFO DEBUG FINE FINER FINEST LogCategoryLevel string In addition. including any calls to System. Valid values are: • Db • Workflow • Validation • Callout • Apex_code • Apex_profiling • All Specifies the amount of information returned in the debug log. a SOAP input header called DebuggingHeader allows you to set the logging granularity according to the levels outlined in the following table. Log Level NONE Description Does not include any log messages.debug(). Includes the request-response XML that the server is sending and receiving from an external Web service. For more information. In addition.debug method. in terms of SOQL and SOSL statements. every DML statement or inline SOQL or SOSL query.Debugging Apex Handling Uncaught Exceptions Log Level DEBUGONLY Description Includes lower level messages. as well as messages generated by calls to the System. This is useful when debugging issues related to using Force. scheduled Apex. These three sections list the locations in the code that consumed the most time. DebuggingInfo. along with the number of times they were executed. DML operations. The developer specified in the LastModifiedBy field receives the error via email with the Apex stack trace and the customer’s organization and user ID. This error message includes the Apex stack trace. such as break and continue • Thrown exceptions * • Static and class initialization code * • Any changes in the with sharing context DB PROFILE CALLOUT DETAIL The corresponding output header. see DebuggingHeader on page 641. Includes log messages generated by calls to the System. 213 . For Apex code that runs asynchronously—batch Apex. in descending order of total cumulative time. No other customer data is returned with the report. See Also: Understanding the Debug Log Working with Logs in the Developer Console Handling Uncaught Exceptions If some Apex code has a bug or does not catch a code-level exception: • • The end user sees a simple explanation of the problem in the application interface. contains the resulting debug log. Includes all messages generated by the PROFILE level as well as the following: • Variable declaration statements • Start of loop executions • All loop controls. and Apex method invocations. or future methods (methods annotated with @future)—error emails for duplicate exceptions don’t get suppressed. some error emails may get suppressed for duplicate exception errors. Note that for Apex code that runs synchronously. the end of the debug log contains overall profiling information for the portions of the request that used the most resources. as well as every data manipulation language (DML) statement or inline SOQL or SOSL query.com Web services API calls. Includes log messages generated by calls to the System.debug method.debug method. and the entrance and exit of every user-defined method. com ISV Partner from Force.000 1. as well as to specific namespaces. the associated governor issues a runtime exception that cannot be handled.com Partner Programs. Description Total number of SOQL queries issued 1 1 Limit 100 200 50. If some Apex code ever exceeds a limit. update. the Apex runtime engine strictly enforces a number of limits to ensure that runaway Apex does not monopolize shared resources.process. if you install a package from AppExchange that is not created by a salesforce. or delete statements4 For loop list batch size Total number of callouts (HTTP requests or Web services calls) in a request Maximum timeout for all callouts (HTTP requests or Web services calls) in a request Default timeout of callouts (HTTP requests or Web services calls) in a request Total number of methods with the future annotation allowed per Apex invocation5 214 . any Apex code in that package can issue up to 150 DML statements while executing.emptyRecycleBin Total number of records processed as a result of DML statements.Debugging Apex Understanding Execution Governors and Limits Understanding Execution Governors and Limits Because Apex runs in a multitenant environment.com AppExchange. For more information on salesforce. Any resources it uses counts against the total for your organization. or 10. meaning more than 150 DML statements might execute during a single request if code from the managed package and your native organization both execute. In addition. Consequently.com ISV Partner packages.000 10. Cumulative resource messages and warning emails are also generated based on managed package namespaces as well. the code from that package does not have its own separate governor limit count. Approval.000 Total number of executed code statements Total number of executed code statements for Batch Apex and future methods Total heap size 3 200. Governor limits apply to an entire organization. the components in the package belong to a namespace unique from other components in your organization. or governors.000. track and enforce the statistics outlined in the following table.000 6 MB 12 MB 16 200 10 120 seconds 10 seconds 10 Total heap size for Batch Apex and future methods Total stack depth for any Apex invocation that recursively fires triggers due to insert. see salesforce.getQueryLocator Total number of SOSL queries issued Total number of records retrieved by a single SOSL query Total number of DML statements issued2 database.com ISV Partner.000 20 200 150 Total number of SOQL queries issued for Batch Apex and future methods Total number of records retrieved by SOQL queries Total number of records retrieved by Database. if you install a managed package created by a salesforce. Conversely. These limits. For example. any Apex code that is native to your organization can also issue up to 150 DML statements. convertLead Database. per 24 hours. suppose your organization has three full Salesforce licenses.delete insert and Database.undelete update and Database.000 method calls every 24 hours.upsert System. separate from the invocation of the code that caused it to fire. Chatter customer users. Recursive Apex that does not fire any triggers with insert. In addition to static SOQL statements. recursive Apex that fires a trigger spawns the trigger in a new Apex invocation.getQueryLocator Database. and 100 Customer Portal User licenses. Because spawning a new invocation of Apex is a more expensive operation than a recursive call in a single invocation. 5 Salesforce also imposes a limit on the number of future method invocations: 200 method calls per full Salesforce user license or Force.countQuery Database. calls to the following methods count against the number of SOQL statements issued in a request. Conversely. there are tighter restrictions on the stack depth of these types of recursive calls. with a single stack.insert merge undelete and Database. calculated as 200 x (3+2). This is an organization-wide limit. Chatter Only. These types of queries have a limit of three times the number for top-level queries. Approval. The row counts from these relationship queries contribute to the row counts of the overall code execution. update. Customer Portal User. For example.emptyRecycleBin Database.update upsert and Database. each parent-child relationship counts as an additional query. • • • 2 Database.runAs • • • • • • • • • • • • 3 4 Email services heap size is 36 MB. two Force.query Calls to the following methods count against the number of DML queries issued in a request.setSavePoint delete and Database. or delete statements exists in a single invocation. not 200 x (3+2+100). Your entire organization is limited to only 1. 215 .com App Subscription user license.com App Subscription licenses. and partner portal User licenses aren’t included in this limit calculation.process Database.Debugging Apex Understanding Execution Governors and Limits Description Maximum size of callout request or response (HTTP request or Web services call) Total number of sendEmail methods allowed Total number of describes allowed7 Total number of classes that can be scheduled concurrently Total number of test classes that can be queued per a 24-hour period8 6 Limit 3 MB 10 100 25 The greater of 500 or 10 multiplied by the number of test classes in the organization 1 In a SOQL query with parent-child relationship sub-queries.rollback Database. Debugging Apex Understanding Execution Governors and Limits 6 7 The HTTP request and response sizes count towards the total heap size. Describes include the following methods and objects. ChildRelationship objects RecordTypeInfo objects PicklistEntry objects fields calls fieldsets calls • • • • • 8 This limit applies to tests running asynchronously. This includes tests started through the Salesforce user interface including the Developer Console or by inserting ApexTestQueueItem objects using SOAP API. Limits apply individually to each testMethod. Use the Limits methods to determine the code execution limits for your code while it is running. For example, you can use the getDMLStatements method to determine the number of DML statements that have already been called by your program, or the getLimitDMLStatements method to determine the total number of DML statements available to your code. For best performance, SOQL queries must be selective, particularly for queries inside of triggers. To avoid long execution times, non-selective SOQL queries may be terminated by the system. Developers will receive an error message when a non-selective query in a trigger executes against an object that contains more than 100,000 records. To avoid this error, ensure that the query is selective. See More Efficient SOQL Queries. For Apex saved using Salesforce.com API version 20.0 or earlier, if an API call causes a trigger to fire, the batch of 200 records to process is further split into batches of 100 records. For Apex saved using Salesforce.com API version 21.0 and later, no further splits of API batches occur. Note that static variable values are reset between batches, but governor limits are not. Do not use static variables to track state information between batches. In addition to the execution governor limits, Apex has the following limits. • • • The maximum number of characters for a class is 1 million. The maximum number of characters for a trigger is 1 million. The maximum amount of code used by all Apex code in an organization is 3 MB. Note: This limit does not apply to certified managed packages installed from AppExchange, (that is, an app that has been marked AppExchange Certified). The code in those types of packages belong to a namespace unique from the code in your organization. For more information on AppExchange Certified packages, see the Force.com AppExchange online help. This limit also does not apply to any code included in a class defined with the @isTest annotation. • • • • There is a limit on the method size. Large methods that exceed the allowed limit cause an exception to be thrown during the execution of your code. Like in Java, the method size limit in Apex is 65,535 bytecode instructions in compiled form. If a SOQL query runs more than 120 seconds, the request can be canceled by Salesforce. Each Apex request is limited to 10 minutes of execution. A callout request is limited to a maximum of 20 simultaneous requests to URLs with the same host. The host is defined by the unique subdomain for the URL, for example, www.mysite.com and extra.mysite.com are two different hosts. This limit is calculated across all organizations that access the same host. If this limit is exceeded, a CalloutException will be thrown. The maximum number of records that an event report returns for a user who is not a system administrator is 20,000, for system administrators, 100,000. • 216 Debugging Apex Understanding Execution Governors and Limits • • Each organization is allowed 10 synchronous concurrent requests for long-running requests that last longer than 5 seconds. If additional requests are made while the 10 long-running requests are still running, they are denied. A user can have up to 50 query cursors open at a time. For example, if 50 cursors are open and a client application still logged in as the same user attempts to open a new one, the oldest of the 50 cursors is released. Note that this limit is different for the batch Apex start method, which can have up to five query cursors open at a time per user. The other batch Apex methods have the higher limit of 50 cursors. Cursor limits for different Force.com features are tracked separately. For example, you can have 50 Apex query cursors, 50 batch cursors, and 50 Visualforce cursors open at the same time. • • • In a single transaction, you can only reference 10 unique namespaces. For example, suppose you have an object that executes a class in a managed package when the object is updated. Then that class updates a second object, which in turn executes a different class in a different package. Even though the second package wasn’t accessed directly by the first, because it occurs in the same transaction, it’s included in the number of namespaces being accessed in a single transaction. Any deployment of Apex is limited to 5,000 code units of classes and triggers. If you use the Data.com Clean product and its automated jobs, and you have set up Apex triggers with SOQL queries to run when account, contact, or lead records, the queries may interfere with Clean jobs for those objects. Your Apex triggers (combined) should not exceed 200 SOQL queries per batch. If they do, your Clean job for that object will fail. In addition, if your triggers call future methods, they will be subject to a limit of 10 future calls per batch. Email Limits Inbound Email Limits Email Services: Maximum Number of Email Messages Processed (Includes limit for On-Demand Email-to-Case) Number of user licenses multiplied by Number of user licenses multiplied by 1,000, up to a daily maximum of 1,000,000 10 MB1 10 MB Email Services: Maximum Size of Email Message (Body and Attachments) On-Demand Email-to-Case: Maximum Email Attachment Size On-Demand Email-to-Case: Maximum Number of Email Messages Processed Number of user licenses multiplied by 1,000, up to a daily maximum of (Counts toward limit for Email Services) 1,000,000 1 The maximum size of email messages for Email Services varies depending on language and character set. When defining email services, note the following: • • An email service only processes messages it receives at one of its addresses. Salesforce limits the total number of messages that all email services combined, including On-Demand Email-to-Case, can process daily. Messages that exceed this limit are bounced, discarded, or queued for processing the next day, depending on how you configure the failure response settings for each email service. Salesforce calculates the limit by multiplying the number of user licenses by 1,000, up to a daily maximum of 1,000,000. For example, if you have ten licenses, your organization can process up to 10,000 email messages a day. Email service addresses that you create in your sandbox cannot be copied to your production organization. For each email service, you can tell Salesforce to send error email messages to a specified address instead of the sender's email address. Email services rejects email messages and notifies the sender if the email (combined body text, body HTML and attachments) exceeds approximately 10 MB (varies depending on language and character set). • • • 217 Debugging Apex Understanding Execution Governors and Limits Outbound Email: Limits for Single and Mass Email Sent Using Apex You can send single emails to a maximum of 1,000 external email addresses per day based on Greenwich Mean Time (GMT). Single emails sent using the application don't count towards this limit. You can send mass email to a total of 1,000 external email addresses per day per organization based on Greenwich Mean Time (GMT). The maximum number of external addresses you can include in each mass email depends on the Edition of Salesforce you are using: Edition Professional Enterprise Edition Unlimited Edition Address Limit per Mass Email 250 500 1,000 Note: Note the following about email limits: • • • The single and mass email limits don't take unique addresses into account. For example, if you have
[email protected] in your email 10 times, that counts as 10 against the limit. You can send an unlimited amount of email to your internal users. These limits also apply to emails sent using the API and Apex. In Developer Edition organizations and organizations evaluating Salesforce during a trial period, your organization can send mass email to no more than 10 external email addresses per day. This lower limit does not apply if your organization was created before the Winter '12 release and already had mass email enabled with a higher limit. Batch Apex Governor Limits Keep in mind the following governor limits for batch Apex: • • Up to five queued or active batch jobs are allowed for Apex. A user can have up to 50 query cursors open at a time. For example, if 50 cursors are open and a client application still logged in as the same user attempts to open a new one, the oldest of the 50 cursors is released. Note that this limit is different for the batch Apex start method, which can have up to five query cursors open at a time per user. The other batch Apex methods have the higher limit of 50 cursors. Cursor limits for different Force.com features are tracked separately. For example, you can have 50 Apex query cursors, 50 batch cursors, and 50 Visualforce cursors open at the same time. • • A maximum of 50 million records can be returned in the Database.QueryLocator object. If more than 50 million records are returned, the batch job is immediately terminated and marked as Failed. If the start method returns a QueryLocator, the optional scope parameter of Database.executeBatch can have a maximum value of 2,000. If set to a higher value, Salesforce chunks the records returned by the QueryLocator into smaller batches of up to 2,000 records. If the start method returns an iterable, the scope parameter value has no upper limit; however, if you use a very high number, you may run into other limits. If no size is specified with the optional scope parameter of Database.executeBatch, Salesforce chunks the records returned by the start method into batches of 200, and then passes each batch to the execute method. Apex governor limits are reset for each execution of execute. The start, execute, and finish methods can implement up to 10 callouts each. Batch executions are limited to 10 callouts per method execution. The maximum number of batch executions is 250,000 per 24 hours. • • • • 218 Debugging Apex Using Governor Limit Email Warnings • Only one batch Apex job's start method can run at a time in an organization. Batch jobs that haven’t started yet remain in the queue until they're started. Note that this limit doesn’t cause any batch job to fail and execute methods of batch Apex jobs still run in parallel if more than one job is running. See Also: What are the Limitations of Apex? Future Annotation Scheduling Data.com Clean Jobs (Data.com Clean Only) Using Governor Limit Email Warnings When an end-user invokes Apex code that surpasses more than 50% of any governor limit, you can specify a user in your organization to receive an email notification of the event with additional details. To enable email warnings: 1. 2. 3. 4. 5. Log in to Salesforce as an administrator user. Click Your Name > Setup > Manage Users > Users. Click Edit next to the name of the user who should receive the email notifications. Select the Send Apex Warning Emails option. Click Save. 219 Chapter 9 Developing Apex in Managed Packages In this chapter ... • • • Package Versions Deprecating Apex Behavior in Package Versions A package is a container for something as small as an individual component or as large as a set of related apps. After creating a package, you can distribute it to other Salesforce users and organizations, including those outside your company. An organization can create a single managed package that can be downloaded and installed by many different organizations. Managed packages differ from unmanaged packages by having some locked components, allowing the managed package to be upgraded later. Unmanaged packages do not include locked components and cannot be upgraded. This section includes the following topics related to developing Apex in managed packages: • • • Package Versions Deprecating Apex Behavior in Package Versions 220 Developing Apex in Managed Packages Package Versions Package Versions A package version is a number that identifies the set of components uploaded in a package. The version number has the format majorNumber.minorNumber.patchNumber (for example, 2.1.3). The major and minor numbers increase to a chosen value during every major release. The patchNumber is generated and updated only for a patch release. Unmanaged packages are not upgradeable, so each package version is simply a set of components for distribution. A package version has more significance for managed packages. Packages can exhibit different behavior for different versions. Publishers can use package versions to evolve the components in their managed packages gracefully by releasing subsequent package versions without breaking existing customer integrations using the package. When an existing subscriber installs a new package version, there is still only one instance of each component in the package, but the components can emulate older versions. For example, a subscriber may be using a managed package that contains an Apex class. If the publisher decides to deprecate a method in the Apex class and release a new package version, the subscriber still sees only one instance of the Apex class after installing the new version. However, this Apex class can still emulate the previous version for any code that references the deprecated method in the older version. Note the following when developing Apex in managed packages: • The code contained in an Apex class or trigger that is part of a managed package is automatically obfuscated and cannot be viewed in an installing organization. The only exceptions are methods declared as global, meaning that the method signatures can be viewed in an installing organization. Managed packages receive a unique namespace. This namespace is automatically prepended to your class names, methods, variables, and so on, which helps prevent duplicate names in the installer’s organization. In a single transaction, you can only reference 10 unique namespaces. For example, suppose you have an object that executes a class in a managed package when the object is updated. Then that class updates a second object, which in turn executes a different class in a different package. Even though the second package wasn’t accessed directly by the first, because it occurs in the same transaction, it’s included in the number of namespaces being accessed in a single transaction. Package developers can use the deprecated annotation to identify methods, classes, exceptions, enums, interfaces, and 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. You can write test methods that change the package version context to a different package version by using the system method runAs. You cannot add a method to a global interface or an abstract method to a global class after the interface or class has been uploaded in a Managed - Released package version. If the class in the Managed - Released package is virtual, the method that you can add to it must also be virtual and must have an implementation. Apex code contained in an unmanaged package that explicitly references a namespace cannot be uploaded. • • • • • • Deprecating Apex Package developers can use the deprecated annotation to identify methods, classes, exceptions, enums, interfaces, and 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. After you upload another package version as Managed - Released, new subscribers that install the latest package version cannot see the deprecated elements, while the elements continue to function for existing subscribers and API integrations. A deprecated item, such as a method or a class, can still be referenced internally by the package developer. 221 Developing Apex in Managed Packages Behavior in Package Versions Note: You cannot use the deprecated annotation in Apex classes or triggers in unmanaged packages. Package developers can use Managed - Beta package versions for evaluation and feedback with a pilot set of users in different Salesforce organizations. If a developer deprecates an Apex identifier and then uploads a version of the package as Managed - Beta, subscribers that install the package version still see the deprecated identifier in that package version. If the package developer subsequently uploads a Managed - Released package version, subscribers will no longer see the deprecated identifier in the package version after they install it. Behavior in Package Versions A package component can exhibit different behavior in different package versions. This behavior versioning allows you to add new components to your package and refine your existing components, while still ensuring that your code continues to work seamlessly for existing subscribers. If a package developer adds a new component to a package and uploads a new package version, the new component is available to subscribers that install the new package version. Versioning Apex Code Behavior Package developers can use conditional logic in Apex classes and triggers to exhibit different behavior for different versions. This allows the package developer to continue to support existing behavior in classes and triggers in previous package versions while continuing to evolve the code. When subscribers install multiple versions of your package and write code that references Apex classes or triggers in your package, they must select the version they are referencing. Within the Apex code that is being referenced in your package, you can conditionally execute different code paths based on the version setting of the calling Apex code that is making the reference. The package version setting of the calling code can be determined within the package code by calling the System.requestVersion method. In this way, package developers can determine the request context and specify different behavior for different versions of the package. The following sample uses the System.requestVersion method and instantiates the System.Version class to define different behaviors in an Apex trigger for different package versions. trigger oppValidation on Opportunity (before insert, before update) { for (Opportunity o : Trigger.new){ // Add a new validation to the package // Applies to versions of the managed package greater than 1.0 if (System.requestVersion().compareTo(new Version(1,0)) > 0) { if (o.Probability >= 50 && o.Description == null) { o.addError('All deals over 50% require a description'); } } // Validation applies to all versions of the managed package. if (o.IsWon == true && o.LeadSource == null) { o.addError('A lead source must be provided for all Closed Won deals'); } } } 222 Developing Apex in Managed Packages Apex Code Items that Are Not Versioned For a full list of methods that work with package versions, see Version Methods and the System.requestVersion method in System Methods. The request context is persisted if a class in the installed package invokes a method in another class in the package. For example, a subscriber has installed a GeoReports package that contains CountryUtil and ContinentUtil Apex classes. The subscriber creates a new GeoReportsEx class and uses the version settings to bind it to version 2.3 of the GeoReports package. If GeoReportsEx invokes a method in ContinentUtil which internally invokes a method in CountryUtil, the request context is propagated from ContinentUtil to CountryUtil and the System.requestVersion method in CountryUtil returns version 2.3 of the GeoReports package. Apex Code Items that Are Not Versioned You can change the behavior of some Apex items across package versions. For example, you can deprecate a method so that new subscribers can no longer reference the package in a subsequent version. However, the following list of modifiers, keywords, and annotations cannot be versioned. If a package developer makes changes to one of the following modifiers, keywords, or annotations, the changes are reflected across all package versions. There are limitations on the changes that you can make to some of these items when they are used in Apex code in managed packages. Package developers can add or remove the following items: • • • • • @future @isTest with sharing without sharing transient Package developers can make limited changes to the following items: • • • • • private—can be changed to global public—can be changed to global protected—can be changed to global abstract—can be changed to virtual but cannot be removed final—can be removed but cannot be added Package developers cannot remove or change the following items: • • global virtual Package developers can add the webService keyword, but once it has been added, it cannot be removed. Note: You cannot deprecate webService methods or variables in managed package code. 223 Developing Apex in Managed Packages Testing Behavior in Package Versions Testing Behavior in Package Versions When you change the behavior in an Apex class or trigger for different package versions, it is important to test that your code runs as expected in the different package versions. You can write test methods that change the package version context to a different package version by using the system method runAs. You can only use runAs in a test method. The following sample shows a trigger with different behavior for different package versions. trigger oppValidation on Opportunity (before insert, before update) { for (Opportunity o : Trigger.new){ // Add a new validation to the package // Applies to versions of the managed package greater than 1.0 if (System.requestVersion().compareTo(new Version(1,0)) > 0) { if (o.Probability >= 50 && o.Description == null) { o.addError('All deals over 50% require a description'); } } // Validation applies to all versions of the managed package. if (o.IsWon == true && o.LeadSource == null) { o.addError('A lead source must be provided for all Closed Won deals'); } } } The following test class uses the runAs method to verify the trigger's behavior with and without a specific version: @isTest private class OppTriggerTests{ static testMethod void testOppValidation(){ // Set up 50% opportunity with no description Opportunity o = new Opportunity(); o.Name = 'Test Job'; o.Probability = 50; o.StageName = 'Prospect'; o.CloseDate = System.today(); // Test running as latest package version try{ insert o; } catch(System.DMLException e){ System.assert( e.getMessage().contains( 'All deals over 50% require a description'), e.getMessage()); } // Run test as managed package version 1.0 System.runAs(new Version(1,0)){ try{ insert o; } catch(System.DMLException e){ System.assert(false, e.getMessage()); } } // Set up a closed won opportunity with no lead source 224 Developing Apex in Managed Packages Testing Behavior in Package Versions o = new Opportunity(); o.Name = 'Test Job'; o.Probability = 50; o.StageName = 'Prospect'; o.CloseDate = System.today(); o.StageName = 'Closed Won'; // Test running as latest package version try{ insert o; } catch(System.DMLException e){ System.assert( e.getMessage().contains( 'A lead source must be provided for all Closed Won deals'), e.getMessage()); } // Run test as managed package version 1.0 System.runAs(new Version(1,0)){ try{ insert o; } catch(System.DMLException e){ System.assert( e.getMessage().contains( 'A lead source must be provided for all Closed Won deals'), e.getMessage()); } } } } 225 Chapter 10 Exposing Apex Methods as SOAP Web Services In this chapter ... • WebService Methods You can expose your Apex methods as SOAP Web services so that external applications can access your code and your application. To expose your Apex methods, use WebService Methods. Tip: • Apex SOAP Web services allow an external application to invoke Apex methods through SOAP Web services. Apex callouts enable Apex to invoke external Web or HTTP services. Apex REST API exposes your Apex classes and methods as REST Web services. See Exposing Apex Classes as REST Web Services. • 226 Exposing Apex Methods as SOAP Web Services WebService Methods WebService Methods Apex class methods can be exposed as custom SOAP Web service calls. This allows an external application to invoke an Apex Web service to perform an action in Salesforce. Use the webService keyword to define these methods. For example: global class MyWebService { webService static Id makeContact(String lastName, Account a) { Contact c = new Contact(lastName = 'Weissman', AccountId = a.Id); insert c; return c.id; } } A developer of an external application can integrate with an Apex class containing webService methods by generating a WSDL for the class. To generate a WSDL from an Apex class detail page: 1. In the application navigate to Your Name > Setup > Develop > Apex Classes. 2. Click the name of a class that contains webService methods. 3. Click Generate WSDL. Exposing Data with WebService Methods Invoking a custom webService method always uses system context. Consequently, the current user's credentials are not used, and any user who has access to these methods can use their full power, regardless of permissions, field-level security, or sharing rules. Developers who expose methods with the webService keyword should therefore take care that they are not inadvertently exposing any sensitive data. Warning: Apex class methods that are exposed through the API with the webService keyword don't enforce object permissions and field-level security by default. We recommend that you make use of the appropriate object or field describe result methods to check the current user’s access level on the objects and fields that the webService method is accessing. See Schema.DescribeSObjectResult and Schema.DescribeFieldResult. Also, sharing rules (record-level access) are enforced only when declaring a class with the with sharing keyword. This requirement applies to all Apex classes, including to classes that contain webService methods. To enforce sharing rules for webService methods, declare the class that contains these methods with the with sharing keyword. See Using the with sharing or without sharing Keywords. Considerations for Using the WebService Keyword When using the webService keyword, keep the following considerations in mind: • • • • • You cannot use the webService keyword when defining a class. However, you can use it to define top-level, outer class methods, and methods of an inner class. You cannot use the webService keyword to define an interface, or to define an interface's methods and variables. System-defined enums cannot be used in Web service methods. You cannot use the webService keyword in a trigger because you cannot define a method in a trigger. All classes that contain methods defined with the webService keyword must be declared as global. If a method or inner class is declared as global, the outer, top-level class must also be defined as global. 227 Exposing Apex Methods as SOAP Web Services Considerations for Using the WebService Keyword • • • • Methods defined with the webService keyword are inherently global. These methods can be used by any Apex code that has access to the class. You can consider the webService keyword as a type of access modifier that enables more access than global. You must define any method that uses the webService keyword as static. You cannot deprecate webService methods or variables in managed package code. Because there are no SOAP analogs for certain Apex elements, methods defined with the webService keyword cannot take the following elements as parameters. While these elements can be used within the method, they also cannot be marked as return values. ◊ ◊ ◊ ◊ ◊ Maps Sets Pattern objects Matcher objects Exception objects • • • You must use the webService keyword with any member variables that you want to expose as part of a Web service. You should not mark these member variables as static. Salesforce denies access to Web service and executeanonymous requests from an AppExchange package that has Restricted access. Apex classes and triggers saved (compiled) using API version 15.0 and higher produce a runtime error if you assign a String value that is too long for the field. The following example shows a class with Web service member variables as well as a Web service method: global class SpecialAccounts { global class AccountInfo { webService String AcctName; webService Integer AcctNumber; } webService static Account createAccount(AccountInfo info) { Account acct = new Account(); acct.Name = info.AcctName; acct.AccountNumber = String.valueOf(info.AcctNumber); insert acct; return acct; } webService static Id [] createAccounts(Account parent, Account child, Account grandChild) { insert parent; child.parentId = parent.Id; insert child; grandChild.parentId = child.Id; insert grandChild; Id [] results = new Id[3]; results[0] = parent.Id; results[1] = child.Id; results[2] = grandChild.Id; return results; } testMethod static void testAccountCreate() { AccountInfo info = new AccountInfo(); info.AcctName = 'Manoj Cheenath'; 228 229 . see Apex in AJAX on page 99. Consequently. Account acct = SpecialAccounts. Apex does not allow two methods marked with the webService keyword to have the same name.assert(acct != null). Overloading Web Service Methods SOAP and WSDL do not provide good support for overloading methods. Web service methods that have the same name in the same class generate a compile-time error.AcctNumber = 12345.Exposing Apex Methods as SOAP Web Services Overloading Web Service Methods info. System. For more information.createAccount(info). } } You can invoke this Web service using AJAX. • • • • • Introduction to Apex REST Apex REST Annotations Apex REST Methods Exposing Data with Apex REST Web Service Methods Apex REST Code Samples You can expose your Apex classes and methods so that external applications can access your code and your application through the REST architecture. You'll learn about the class and method annotations and see code samples that show you how to implement this functionality..Chapter 11 Exposing Apex Classes as REST Web Services In this chapter . This section provides an overview of how to expose your Apex classes as REST Web services. 230 .. and the format is indicated by the Content-Type property in the HTTP header. Only the following return and parameter types are allowed: • • • Apex primitives (excluding sObject and Blob). JSON representations are passed by default in the body of a request or response. the resource representation is serialized into the response body. see Apex REST Annotations on page 132 Governor Limits Calls to Apex REST classes count against the organization's API governor limits. see Understanding Execution Governors and Limits. • • • • • • @RestResource(urlMapping='/yourUrl') @HttpDelete @HttpGet @HttpPatch @HttpPost @HttpPut Apex REST Methods Apex REST supports two formats for representations of resources: JSON and XML. For more information. the maximum request or response size is 3 MB. For example. If parameters are defined in the Apex method. Apex REST Annotations Six new annotations have been added that enable you to expose an Apex class as a RESTful Web service.0 Session ID See Step Two: Set Up Authorization in the REST API Developer's Guide. If the Apex method has a non-void return type. All standard Apex governor limits apply to Apex REST classes. You can retrieve the body as a Blob from the HttpRequest object if there are no parameters to the Apex method. an attempt is made to deserialize the request body into those parameters. add annotations to your methods to expose them through REST. sObjects Lists or maps of Apex primitives or sObjects (only maps with String keys are supported) 231 . Similarly.Exposing Apex Classes as REST Web Services Introduction to Apex REST Introduction to Apex REST You can expose your Apex class and methods so that external applications can access your code and your application through the REST architecture. Authentication Apex REST supports these authentication mechanisms: • • OAuth 2. This is done by defining your Apex class with the @RestResource annotation to expose it as a REST resource. For more information. An Apex method with a non-void return type will have the return value serialized into RestResponse. global String string2 { get. This example shows how to access these objects through RestContext: RestRequest req = RestContext. If the method has parameters. • RestRequest and RestResponse objects are available by default in your Apex methods through the static RestContext object.com/services/apexrest/packageNamespace/MyMethod/. • • • If the Apex method has no parameters.requestBody property. or global class member variables of the user-defined type. Apex REST methods can be used in managed and unmanaged packages. if the class is contained in a managed package namespace called packageNamespace and the Apex REST methods use a URL mapping of /MyMethod/*. This is because GET and DELETE requests have no request body. an Apex REST method that contains a user-defined type parameter might look like the following: @RestResource(urlMapping='/user_defined_type_example/*') global with sharing class MyOwnTypeRestResource { @HttpPost global static MyUserDefinedClass echoMyType(MyUserDefinedClass ic) { return ic.request. When calling Apex REST methods that are contained in a managed package. User-Defined Types You can use user-defined types for parameters in your Apex REST methods. global static String staticString.response.requestBody property. set.responseBody. the same class can't have two methods annotated with @HttpGet. then Apex REST attempts to deserialize the data into those parameters and the data won't be deserialized into the RestRequest.salesforce. unless the variable is declared as static or transient. Apex REST deserializes request data into public. } private String privateString. For more information about managed packages. you need to include the managed package namespace in the REST call URL.Exposing Apex Classes as REST Web Services Apex REST Methods • User-defined types that contain member variables of the types listed above. For example. Apex REST Method Considerations Here are a few points to consider when you define Apex REST methods. } global class MyUserDefinedClass { global String string1. Methods annotated with @HttpGet or @HttpDelete should have no parameters. so there's nothing to deserialize. Note: Apex REST currently doesn't support requests of Content-Type multipart/form-data. A single Apex class annotated with @RestResource can't have multiple methods annotated with the same HTTP request method. global transient String transientString. Apex REST copies the HTTP request body into the RestRequest. private. } 232 . RestResponse res = RestContext. For example. see Developing Apex in Managed Packages. Apex REST uses similar serialization logic for the response. For example. the URL used via REST to call these methods would be of the form https://instance. userDef2 = def2. sObjects Lists or maps of Apex primitives or sObjects (only maps with String keys are supported) When creating user-defined types used as Apex REST method parameters.Exposing Apex Classes as REST Web Services Apex REST Methods } Valid JSON and XML request data for this method would look like: { "ic" : { "string1" : "value for string1". Apex REST detects a cycle between instances of def1 and def2. or global class member variables must be types allowed by Apex REST: • • • Apex primitives (excluding sObject and Blob). and generates an HTTP 400 status code error response. } } The code in the previous example compiles. } global class MyUserDef2 { MyUserDef1 userDef1.userDef1 = def1. Here's a simple example: @RestResource(urlMapping='/CycleExample/*') global with sharing class ApexRESTCycleExample { @HttpGet global static MyUserDef1 doCycleTest() { MyUserDef1 def1 = new MyUserDef1(). return def1. an HTTP 400 status code response is generated. avoid introducing any class member variable definitions that result in cycles (definitions that depend on each other) at run time in your user-defined types. "string2" : "value for string2". "privateString" : "value for privateString" } } <request> <ic> <string1>value for string1</string1> <string2>value for string2</string2> <privateString>value for privateString</privateString> </ic> </request> If a value for staticString or transientString is provided in the example request data above. Note that the public. private. but at run time when a request is made. } global class MyUserDef1 { MyUserDef2 userDef2. def2. def1. MyUserDef2 def2 = new MyUserDef2(). Request Data Considerations Some additional things to keep in mind for the request data for your Apex REST methods: 233 . However. 123. Boolean b1. you can use these types with JSON. valid values for Boolean parameters are: true. Any other values for Boolean parameters result in an error. for user-defined types. } global class MyUserDef1 { Integer i. For example. false • • • Some parameter and return types can't be used with XML as the Content-Type for the request or as the accepted format for the response. "my second string". If the JSON or XML request data contains multiple parameters of the same name. this results in an HTTP 400 status code error response. the following JSON request data results in an error: { "x" : "value1". String s2) { "s1" "i1" "s2" "b1" } <request> <s1>my first string</s1> <i1>123</i1> <s2>my second string</s2> <b1>false</b1> </request> : : : : "my first string". although the order doesn’t. an HTTP 415 status code is returned. Integer i1. For request data in either JSON or XML. false (both of these are treated as case-insensitive). an HTTP 406 status code is returned. valid requests in both XML and JSON look like the following: @HttpPost global static void myPostMethod(String s1. "x" : "value2" } Similarly. } } 234 . If the parameter list includes a type that's invalid for XML and XML is sent. For example. and hence. if your method specifies an input parameter named x.Exposing Apex Classes as REST Web Services Apex REST Methods • The name of the Apex parameters matter. For example. this results in an error. methods with these parameter or return types can't be used with XML. for example. Maps or collections of collections. if the request data includes data for the same user-defined type member variable multiple times. given this Apex REST method and user-defined type: @RestResource(urlMapping='/DuplicateParamsExample/*') global with sharing class ApexRESTDuplicateParamsExample { @HttpPost global static MyUserDef1 doDuplicateParamsTest(MyUserDef1 def) { return def. List<List<String>> aren't supported. 1 and 0 (the numeric values. not strings of “1” or “0”). If the return type is a type that's invalid for XML and XML is the requested response format. An unhandled user exception occurred. POST. Request Method GET PATCH PATCH DELETE. if you define an Apex REST method such as: @RestResource(urlMapping='/namespaceExample/*') global class MyNamespaceTest { @HttpPost global static MyUDT echoTest(MyUDT def. GET. GET. you can specify null as the value. you must use the http://www. In JSON.org/2001/XMLSchema-instance namespace with a nil value.w3. PATCH.sforce. } } You can use the following XML request data: <request> <def xmlns:MyUDT="http://soap. PUT DELETE. So. 235 . "i" : 2 } } • • If you need to specify a null value for one of your parameters in your request data. The request was successful and the return type is non-void. Response Status Codes The status code of a response is set automatically. In XML. The request was successful and the return type is void. } global class MyUDT { Integer count.com/schemas/class/MyNamespaceTest"> <MyUDT:count>23</MyUDT:count> </def> <extraString>test</extraString> </request> For more information on XML namespaces and Apex. POST. you must specify an XML namespace that references any Apex namespace your method uses.Exposing Apex Classes as REST Web Services Apex REST Methods The following JSON request data also results in an error: { "def" : { "i" : 1. see XML Namespaces. You don't have access to the specified Apex class. see RestResponse Methods. you can either omit the parameter entirely or specify a null value. PATCH. PUT Response Status Code 200 200 204 400 403 Description The request was successful. For the full list of response status codes. String extraString) { return def. for example. For XML request data. This table lists some HTTP status codes and what they mean in the context of the HTTP request method. Warning: Apex class methods that are exposed through the Apex REST API don't enforce object permissions and field-level security by default. PUT DELETE. The XML return type specified for format is unsupported. PATCH. PATCH. See Schema. The URL extension is unsupported. or sharing rules. The Content-Header Type specified in the HTTP request header is unsupported. POST. the current user's credentials are not used.DescribeSObjectResult and Schema. field-level security. POST. POST. PUT DELETE.DescribeFieldResult. POST. The Content-Type property in the header was set to a value other than JSON or XML. The request method doesn't have a corresponding Apex method.Exposing Apex Classes as REST Web Services Exposing Data with Apex REST Web Service Methods Request Method DELETE. PATCH. PATCH. GET. This requirement applies to all Apex classes. POST. POST. GET. To enforce sharing rules for Apex REST API methods. GET. GET. Consequently. PUT DELETE. 236 . POST. PATCH. PUT DELETE. regardless of permissions. The header specified in the HTTP request is not supported. GET. PATCH. declare the class that contains these methods with the with sharing keyword. PATCH. Exposing Data with Apex REST Web Service Methods Invoking a custom Apex REST Web service method always uses system context. PUT GET. sharing rules (record-level access) are enforced only when declaring a class with the with sharing keyword. The Apex class with the specified namespace couldn't be found. PUT DELETE. POST. GET. PUT DELETE. PUT Response Status Code 404 404 404 405 406 406 406 415 415 500 Description The URL is unmapped in an existing @RestResource annotation. including to classes that are exposed through Apex REST API. POST. PATCH. GET. PUT DELETE. POST. PATCH. The XML parameter type is unsupported. PUT DELETE. and any user who has access to these methods can use their full power. Developers who expose methods using the Apex REST annotations should therefore take care that they are not inadvertently exposing any sensitive data. We recommend that you make use of the appropriate object or field describe result methods to check the current user’s access level on the objects and fields that the Apex REST API method is accessing. Also. See Using the with sharing or without sharing Keywords. GET. An unhandled Apex exception occurred. GET. PATCH. String website) { Account account = new Account(). RestResponse res = RestContext. String accountId = req. insert account. Account result = [SELECT Id. delete account.request. Name. Apex REST Code Sample Using RestRequest: Provides an example of an Apex REST class that adds an attachment to a record by using the RestRequest object Apex REST Basic Code Sample This sample shows you how to implement a simple REST API in Apex that handles three different HTTP request methods. To call the doGet method from a client. and update a record. String phone.response. For more information about authenticating with cURL.requestURI. • • Apex REST Basic Code Sample: Provides an example of an Apex REST class with three methods that you can call to delete a record.requestURI. } @HttpGet global static Account doGet() { RestRequest req = RestContext. return account. account.Name = name. Create an Apex class in your instance. } } 2.website = website. by clicking Your Name > Setup > Develop > Apex Classes > New and add this code to your new class: @RestResource(urlMapping='/Account/*') global with sharing class MyRestResource { @HttpDelete global static void doDelete() { RestRequest req = RestContext.requestURI.Id.requestURI.com/services/apexrest/Account/accountId" 237 .Exposing Apex Classes as REST Web Services Apex REST Code Samples Apex REST Code Samples These code samples show you how to expose Apex classes and methods through the REST architecture and how to call those resources from a client. 1.substring(req. account. } @HttpPost global static String doPost(String name. Phone. see the Quick Start section of the REST API Developer's Guide. Website FROM Account WHERE Id = :accountId]. open a command-line window and execute the following cURL command to retrieve an account by ID: curl -H "Authorization: Bearer sessionId" "https://instance. String accountId = req.lastIndexOf('/')+1).phone = phone.salesforce.request. account.substring(req. get a record. Account account = [SELECT Id FROM Account WHERE Id = :accountId]. RestResponse res = RestContext. return result.lastIndexOf('/')+1).response. 5.txt "https://instance.txt to contain the data for the account you will create in the next step. "Name" : "Acme" } Note: The cURL examples in this section don't use a namespaced Apex class so you won't see the namespace in the URL. "Id" : "accountId". Salesforce returns a response with data such as the following: "accountId" The accountId is the ID of the account you just created with the POST request. Replace accountId with the ID of an account which exists in your organization. "url" : "/services/data/v22.com/services/apexrest/Account/" After calling the doPost method. "phone" : "707-555-1234". Create a file called account. Salesforce returns a JSON response with data such as the following: { "attributes" : { "type" : "Account".wingo. In this code. For more information about authenticating with cURL.salesforce.com/services/apexrest/Account/accountId" See Also: Apex REST Annotations Apex REST Code Sample Using RestRequest The following sample shows you how to add an attachment to a case by using the RestRequest object. and the Apex service class accesses the binary data in the RestRequest object . { "name" : "Wingo Ducks". Using a command-line window. Replace instance with your <serverUrl> element. see the Quick Start section of the REST API Developer's Guide. 238 .us" } 4. "website" : "www.salesforce. Using a command-line window. execute the following cURL command to create a new account: curl -H "Authorization: Bearer sessionId" -H "Content-Type: application/json" -d @account. execute the following cURL command to delete an account by specifying the ID: curl —X DELETE —H "Authorization: Bearer sessionId" "https://instance. the binary file data is stored in the RestRequest object.Exposing Apex Classes as REST Web Services Apex REST Code Sample Using RestRequest • • • Replace sessionId with the <sessionId> element that you noted in the login response.0/sobjects/Account/accountId" }.ca. After calling the doGet method. 3. response.requestBody. To verify that the attachment and the image were added to the case. by clicking Your Name > Setup > Develop > Apex Classes. Attachment a = new Attachment (ParentId = caseId. Id caseId = req.requestURI. navigate to Cases and select the All Open Cases view. Open a command-line window and execute the following cURL command to upload the attachment to a case: curl -H "Authorization: Bearer sessionId" -H "X-PrettyPrint: 1" -H "Content-Type: image/jpeg" --data-binary @file "https://instance. Click on the case and then scroll down to the Attachments related list. Replace caseId with the ID of the case you want to add the attachment to. } } 2. Name = 'VehiclePicture'). Body = picture. 239 .lastIndexOf('/')+1). The Apex class returns a JSON response that contains the attachment ID such as the following: "00PD0000001y7BfMAI" 3.Exposing Apex Classes as REST Web Services Apex REST Code Sample Using RestRequest 1.com/services/apexrest/CaseManagement/v1/caseId" • • • • Replace sessionId with the <sessionId> element that you noted in the login response. You should see the attachment you just created. Create an Apex class in your instance. Blob picture = req.salesforce. Replace file with the path and file name of the file you want to attach.jpg "https://na1.salesforce.Id. Your command should look something like this (with the sessionId replaced with your session ID): curl -H "Authorization: Bearer sessionId" -H "X-PrettyPrint: 1" -H "Content-Type: image/jpeg" --data-binary @c:\test\vehiclephoto1.com/services/apexrest/CaseManagement/v1/500D0000003aCts" Note: The cURL examples in this section don't use a namespaced Apex class so you won't see the namespace in the URL.requestURI. Click New and add the following code to your new class: @RestResource(urlMapping='/CaseManagement/v1/*') global with sharing class CaseMgmtService { @HttpPost global static String attachPic(){ RestRequest req = RestContext.request.substring(req. return a. ContentType = 'image/jpg'. RestResponse res = Restcontext. Replace instance with your <serverUrl> element. insert a. Apex Web services allow an external application to invoke Apex methods through Web services. or the callout fails. see: • • SOAP Services: Defining a Class from a WSDL Document on page 241 Invoking HTTP Callouts on page 251 Tip: Callouts enable Apex to invoke external web or HTTP services.. Apex provides integration with Web services that utilize SOAP and WSDL. Salesforce prevents calls to unauthorized network addresses.. • • • • • Adding Remote Site Settings SOAP Services: Defining a Class from a WSDL Document Invoking HTTP Callouts Using Certificates Callout Limits and Limitations An Apex callout enables you to tightly integrate your Apex with an external service by making a call to an external Web service or sending a HTTP request from Apex code and then receiving the response. that site must be registered in the Remote Site Settings page. To learn more about the two types of callouts. 240 . Note: Before any Apex callout can call an external site. or HTTP services (RESTful services).Chapter 12 Invoking Callouts Using Apex In this chapter . 2. Click Generate from WSDL. For security reasons. 4. SOAP Services: Defining a Class from a WSDL Document Classes can be automatically generated from a WSDL document that is stored on a local hard drive or network. or if the resulting classes exceed 1 million character limit on Apex classes.Invoking Callouts Using Apex Adding Remote Site Settings Adding Remote Site Settings Before any Apex callout can call an external site. Click New Remote Site. 3. 2. enter a description of the site. Note: The WSDL document that you specify might contain a SOAP endpoint location that references an outbound port. Optionally. Enter the URL for the remote site. Enter a descriptive term for the Remote Site Name. Click Parse WSDL to verify the WSDL document contents. or type in the full path. 6. To add a remote site setting: 1. Click Browse to navigate to a WSDL document on your local hard drive or network. To generate an Apex class from a WSDL: 1. 4. Use callouts to third-party Web services only when necessary. Click Your Name > Setup > Security Controls > Remote Site Settings. Parsing will fail if the WSDL contains schema types or schema constructs that are not supported by Apex classes. 5. Salesforce prevents calls to unauthorized network addresses. 3. Apex classes can be no more than 1 million characters total. Click Save. 1024–66535 (inclusive): These ports accept HTTP or HTTPS connections. In the application. Creating a class by consuming a WSDL document allows developers to make callouts to the external Web service in their Apex code. the Salesforce SOAP API WSDL cannot be parsed. The application generates a default class name for each namespace in the WSDL document and reports any errors. Modify the class names as desired. For example. While you can save more than one WSDL namespace into a single class by using the same class name for each namespace. 241 . Salesforce restricts the outbound ports you may specify to one of the following: • • • 80: This port only accepts HTTP connections. Note: Use Outbound Messaging to handle integration solutions when possible. This WSDL document is the basis for the Apex class you are creating. 5. 443: This port only accepts HTTPS connections. that site must be registered in the Remote Site Settings page. click Your Name > Setup > Develop > Apex Classes. or the callout fails. For example. These classes allow you to call the external Web service from Apex.RegisteredUser. The following samples work with the sample WSDL file in Understanding the Generated Code on page 246: 242 . Note: Before you can use the samples in the rest of this topic. For example.DNSLookup('www. the generated Apex wraps the elements in an inner class. dns. Note: In API versions 16. along with any errors from other classes. you could write code similar to the following: // Create the stub strikeironIplookup.com'). create an instance of the stub in your Apex code and call the methods on it.Password = 'your-password'. limit in a WSDL document converts to limit_x in the generated Apex class. you can invoke the external service referenced by the WSDL. // Set up the license header dns.UserID = 'you@company. Invoking an External Service To invoke an external service after using its WSDL document to generate an Apex class. regardless of the Content-Type header. The Apex method that represents the WSDL operation returns the inner class instead of the individual elements. For example. The successfully-generated Apex class includes stub and type classes for calling the third-party Web service represented by the WSDL document.LicenseInfo = new strikeiron.0 and earlier. If an operation in the WSDL has an output message with more than one element. For details on handling characters in element names in a WSDL that are not supported in Apex variable names. Click Generate Apex. Since periods (. see Considerations Using WSDLs. HTTP Header Support You can set the HTTP headers on a Web service callout. • • After you have generated a class from the WSDL.DNSInfo info = dns.0 and later.LicenseInfo. you must copy the Apex class docSampleClass from Understanding the Generated Code and add it to your organization.LicenseInfo. Note the following about the generated Apex: • If a WSDL document contains an Apex reserved word. The final page of the wizard shows which classes were successfully generated.com'. To set HTTP headers. HTTP responses are decoded using the encoding specified in the Content-Type header.myname.LicenseInfo.) are not allowed in Apex class names.RegisteredUser(). any periods in WSDL names used to generate Apex classes are replaced by underscores (_) in the generated Apex code. dns. dns.DNSSoap dns = new strikeironIplookup. you can use this feature to set the value of a cookie in an authorization header.RegisteredUser. See Reserved Keywords. The page also provides a link to view successfully generated code. add inputHttpHeaders_x and outputHttpHeaders_x to the stub.DNSSoap(). HTTP responses for callouts are always decoded using UTF-8.RegisteredUser = new strikeiron. In API versions 17. // Make the Web service call strikeironIplookup. the word is appended with _x when the Apex class is generated. to invoke the StrikeIron IP address lookup service from Apex.Invoking Callouts Using Apex Invoking an External Service 6.LicenseInfo(). //Setting a custom HTTP header stub. String>(). Accessing HTTP Response Headers from a Web Service Callout Response docSample. String>(). String input = 'This is the input string'.put('Authorization'. String output = stub.outputHttpHeaders_x. String input = 'This is the input string'.inputHttpHeaders_x.DocSamplePort stub = new docSample.get('Set-Cookie').inputHttpHeaders_x.outputHttpHeaders_x.inputHttpHeaders_x = new Map<String.EchoString(input).outputHttpHeaders_x = new Map<String.DocSamplePort(). //Getting custom header String myHeader = stub. 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==').put('myHeader'. //Setting a basic authentication header stub. Supported WSDL Features Apex supports only the document literal wrapped WSDL style and the following primitive and built-in datatypes: Schema Type xsd:anyURI xsd:boolean xsd:date xsd:dateTime xsd:double xsd:float xsd:int xsd:integer xsd:language Apex Type String Boolean Date Datetime Double Double Integer Integer String 243 . //Setting a cookie header stub.Invoking Callouts Using Apex Supported WSDL Features Sending HTTP Headers on a Web Service Callout docSample. 'myValue').EchoString(input).inputHttpHeaders_x.DocSamplePort stub = new docSample. //Getting cookie header String cookie = stub. stub. The value of outputHttpHeaders_x is null by default. it overrides the standard headers set.put('Cookie'. You must set outputHttpHeaders_x before you have access to the content of headers in the response. stub.get('My-Header'). If a value for inputHttpHeaders_x is specified.DocSamplePort(). String output = stub. 'name=value'). In Apex code saved using API version 15. anyType is mapped to String. • xsd:sequence The following data types are only supported when used as call ins.0 and later xsd:choice. in Apex code saved using API version 15.0 and later. when an external Web service calls an Apex Web service method. the ref attribute is also supported with the following restrictions: ◊ You cannot call a ref in a different namespace.0 and later. ◊ A global element cannot use ref. that is.0 and later xsd:element. For code saved using API version 14. ◊ If an element contains ref. These data types are not supported as callouts. 244 .Invoking Callouts Using Apex Supported WSDL Features Schema Type xsd:long xsd:Name xsd:NCName xsd:nonNegativeInteger xsd:NMTOKEN xsd:NMTOKENS xsd:normalizedString xsd:NOTATION xsd:positiveInteger xsd:QName xsd:short xsd:string xsd:time xsd:token xsd:unsignedInt xsd:unsignedLong xsd:unsignedShort Apex Type Long String String Integer String String String String Integer String Integer String Datetime String Integer Long Integer Note: The Salesforce datatype anyType is not supported in WSDLs used to generate Apex code that is saved using API version 15. that is.0 and later xsd:annotation.0 and earlier. in Apex code saved using API version 15. in Apex code saved using API version 15. Apex also supports the following schema constructs: • • • • • xsd:all. it cannot also contain name or type.0 and later xsd:attribute. in Apex code saved using API version 15. when an Apex Web service method calls an external Web service. .w3. or services. or multiple bindings WSDL files that import external schemas.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://s3. an import within the same schema is supported.com/doc/2006-03-01/"> <xsd:element name="CreateBucket"> <xsd:complexType> <xsd:sequence> [.. For example.org/AccountPollInterface/" xmlns:xsd="http://www. the external WSDL is pasted into the WSDL you are converting: <wsdl:types> <xsd:schema xmlns:tns="http://s3.org/AccountPollInterface/" xmlns:xsd="http://www.w3. types. the following WSDL fragment imports an external schema. multiple services.] </xsd:schema> </wsdl:types> • • • Any schema types not documented in the previous table WSDLs that exceed the size limit. including: • • • RPC/encoded services WSDL files with mulitple portTypes.amazonaws.com/doc/2006-03-01/" xmlns:xsd="http://www. The following WSDL snippet doesn’t use document literal wrapped style and results in an “Unable to find complexType” error when imported. This follows the document literal style and is supported. including the Salesforce WSDLs WSDLs that don’t use the document literal wrapped style.org/2001/XMLSchema"> 245 . <wsdl:types> <xsd:schema targetNamespace="http://test.xsd"/> </xsd:schema> </wsdl:types> However.org/2001/XMLSchema"> <xsd:element name="SFDCPollAccountsResponse" type="tns:SFDCPollResponse"/> <xsd:simpleType name="SFDCPollResponse"> <xsd:restriction base="xsd:string" /> </xsd:simpleType> </xsd:schema> </wsdl:types> This modified version wraps the simpleType element as a complexType that contains a sequence of elements.w3.amazonaws. which is not supported: <wsdl:types> <xsd:schema elementFormDefault="qualified" targetNamespace="http://s3. <wsdl:types> <xsd:schema targetNamespace="http://test.com/doc/2006-03-01/"> <xsd:include schemaLocation="AmazonS3.amazonaws. In the following example.Invoking Callouts Using Apex Supported WSDL Features • • • blob decimal enum Apex does not support any other WSDL constructs. org/wsdl/http/" xmlns:soap="http://schemas.sample.xmlsoap.sample.org/soap/encoding/" xmlns:tns="http://doc.org/wsdl/soap/" xmlns:s="http://www. The following code shows a sample WSDL document: <wsdl:definitions xmlns:http="http://schemas. the schema targetNamespace maps to the Apex class name.com/docSample"> <s:element name="EchoString"> <s:complexType> <s:sequence> <s:element minOccurs="0" maxOccurs="1" name="input" type="s:string" /> </s:sequence> </s:complexType> </s:element> <s:element name="EchoStringResponse"> <s:complexType> <s:sequence> <s:element minOccurs="0" maxOccurs="1" name="EchoStringResult" type="s:string" /> </s:sequence> </s:complexType> </s:element> </s:schema> </wsdl:types> <!--The stub below defines operations.xmlsoap. --> <wsdl:types> <s:schema elementFormDefault="qualified" targetNamespace="http://doc. The Apex class is auto-generated for you when you import the WSDL.com/docSample" xmlns:wsdl="http://schemas. Then.com/docSample" targetNamespace="http://doc.xmlsoap.Invoking Callouts Using Apex Understanding the Generated Code <xsd:element name="SFDCPollAccountsResponse" type="tns:SFDCPollResponse" /> <xsd:complexType name="SFDCPollResponse"> <xsd:sequence> <xsd:element name="SFDCOutput" type="xsd:string" /> </xsd:sequence> </xsd:complexType> </xsd:schema> </wsdl:types> Understanding the Generated Code The following example shows how an Apex class is created from a WSDL document.w3.sample.Above. --> <!-. each element in the complexType is mapped to a public field inside the class. --> <wsdl:message name="EchoStringSoapIn"> <wsdl:part name="parameters" element="tns:EchoString" /> </wsdl:message> <wsdl:message name="EchoStringSoapOut"> <wsdl:part name="parameters" element="tns:EchoStringResponse" /> </wsdl:message> <wsdl:portType name="DocSamplePortType"> <wsdl:operation name="EchoString"> <wsdl:input message="tns:EchoStringSoapIn" /> 246 .org/wsdl/"> <!-.xmlsoap. the type definitions for the parameters are listed. Each complexType and simpleType parameteris mapped to an Apex class inside the parent class for the WSDL.Below.org/2001/XMLSchema" xmlns:soapenc="http://schemas. 'http://www.'1'.Finally.w3.sforce. 'true'}. 'string'. private String[] field_order_type_info = new String[]{ 'EchoStringResult'}. --> <wsdl:binding name="DocSampleBinding" type="tns:DocSamplePortType"> <wsdl:operation name="EchoString"> <soap:operation soapAction="urn:dotnet. which maps to the endpoint in the class --> <wsdl:service name="DocSample"> <wsdl:port name="DocSamplePort" binding="tns:DocSampleBinding"> <soap:address location="http://YourServer/YourService" /> </wsdl:port> </wsdl:service> </wsdl:definitions> From this WSDL document.sample. The class name docSample is the name you specify when importing the WSDL.callouttest.'false'}.com/docSample'. private String[] EchoStringResult_type_info = new String[]{ 'EchoStringResult'. private String[] ns_map_type_info = new String[]{ 'http://doc. the following Apex class is auto-generated. //Generated by wsdl2apex public class docSample { public class EchoStringResponse_element { public String EchoStringResult. public String EchoString(String input) { docSample.Invoking Callouts Using Apex Understanding the Generated Code <wsdl:output message="tns:EchoStringSoapOut" /> </wsdl:operation> </wsdl:portType> <!--The code below defines how the types map to SOAP.org/2001/XMLSchema'.com/docSample'. the code below defines the endpoint.EchoString_element request_x = new docSample.sample. } public class DocSamplePort { public String endpoint_x = 'http://YourServer/YourService'.com/EchoString" style="document" /> <wsdl:input> <soap:body use="literal" /> </wsdl:input> <wsdl:output> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <!-.soap. 'docSample'}.'0'.EchoString_element(). private String[] apex_schema_type_info = new String[]{ 'http://doc. 247 . com/EchoString'. 'urn:dotnet. response_x).EchoStringResponse_element'} ).EchoStringResponse_element response_x.sample. docSample. Testing Web Service Callouts Generated code is saved as an Apex class containing the methods you can invoke for calling the Web service. Each element in the type is a public field in the class. Each operation in the WSDL maps to a public method. including the methods in the generated class. 'EchoStringResponse'.EchoString(input).EchoStringResponse_element>(). private String[] apex_schema_type_info = new String[]{ 'http://doc. String output = stub. Apex provides the built-in WebServiceMock interface and the Test.'0'. new String[]{endpoint_x. } } public class EchoString_element { public String input. return response_x. To deploy or package this Apex class and other accompanying code. 'http://www. 'string'.DocSamplePort stub = new docSample.soap. request_x. response_map_x. By default.sample. 'true'}. request_x. 'EchoString'. 'http://doc. To prevent tests from being skipped and to increase code coverage.w3.setMock method that you can use to receive fake responses in a test method. The following code shows how to call the echoString method on the external server: docSample.com/docSample'.sample.org/2001/XMLSchema'. The class generated above can be used to invoke external Web services. WebServiceCallout. The WSDL port name maps to the stub class.input = input. 'http://doc.get('response_x').put('response_x'. docSample.EchoStringResult. 248 .'1'.callouttest. test methods don’t support Web service callouts and tests that perform Web service callouts are skipped. Each complex type becomes a class.com/docSample'.EchoStringResponse_element> response_map_x = new Map<String. } } Note the following mappings from the original WSDL document: • • • • The WSDL target namespace maps to the Apex class name. String input = 'This is the input string'.DocSamplePort(). response_x = response_map_x.com/docSample'.Invoking Callouts Using Apex Testing Web Service Callouts docSample. 75% of the code must have test coverage.invoke( this. private String[] field_order_type_info = new String[]{'input'}. 'docSample.'false'}. response_map_x. Map<String.sforce. private String[] input_type_info = new String[]{ 'input'. String responseName. as follows: response.Invoking Callouts Using Apex Testing Web Service Callouts Specifying a Mock Response for Testing Web Service Callouts When you create an Apex class from a WSDL. you must call Test. you can instruct the Apex runtime to generate a fake response whenever WebServiceCallout. Map<String. Object> response. Import this WSDL and generate a class called docSample before you save this class.invoke. Object request. This is a full example that shows how to test a Web service callout. For the first argument. String requestName. global class YourWebServiceMockImpl implements WebServiceMock { global void doInvoke( Object stub. // Add response element to the response parameter. @isTest global class WebServiceMockImpl implements WebServiceMock { global void doInvoke( Object stub.put('response_x'. Object> response.invoke is called. String soapAction. In this case. This example is based on the WSDL listed in Understanding the Generated Code. Next. String endpoint. Object request. the callout is not made and you receive the mock response specified in your doInvoke method implementation. Note: If the code that performs the callout is in a managed package. String responseType) { // Create response element from the autogenerated class. the response Map parameter is populated with this fake response. } } Note: • • The class implementing the WebServiceMock interface can be either global or public. Map<String.setMock from a test method in the same package with the same namespace to mock the callout.class. When testing these methods. implement the WebServiceMock interface and specify a fake response that the Apex runtime should send. 249 . implement the WebServiceMock interface and specify the fake response in the doInvoke method. pass a new instance of your interface implementation of WebServiceMock. String responseNS. To do so. pass WebServiceMock. The implementation of the WebServiceMock interface is listed first. responseElement). After this point. Now that you have specified the values of the fake response. which performs the callout to the external service. as follows: Test.class.setMock(WebServiceMock. You can annotate this class with @isTest since it will be used only in test context. instruct the Apex runtime to send this fake response by calling Test.setMock in your test method. which returns the response you specify. Here are the steps in more detail. if a Web service callout is invoked in test context. the response element of the auto-generated class is created and assigned a value. you can exclude it from your organization’s code size limit of 3 MB. and for the second argument. the methods in the auto-generated class call WebServiceCallout. This example implements the doInvoke method. // Populate response element. new YourWebServiceMockImpl()). In this way. First. It calls the callEchoString method in the previous class and verifies that a mock response is received.Invoking Callouts Using Apex Considerations Using WSDLs String endpoint.salesforce.assertEquals('Mock response'. } } See Also: WebServiceMock Interface Considerations Using WSDLs Be aware of the following when generating Apex classes from a WSDL. return echo. // Call the method that invokes a callout String output = WebSvcCallout.put('response_x'. public class WebSvcCallout { public static String callEchoString(String input) { docSample.EchoString(input).EchoStringResult = 'Mock response'. 250 . respElement. @isTest private class WebSvcCalloutTest { @isTest static void testEchoString() { // This causes a fake response to be generated Test. String soapAction. String responseName. output).setMock(WebServiceMock.endpoint_x = 'http://api. String responseType) { docSample. // This invokes the EchoString method in the generated class String echo = sample.NET works.EchoStringResponse_element().class. String responseNS. new WebServiceMockImpl()).DocSamplePort sample = new docSample.EchoStringResponse_element respElement = new docSample. // Verify that a fake result is returned System. response. Mapping Headers Headers defined in the WSDL document become public fields on the stub in the generated class.DocSamplePort(). } } This is the test class containing the test method that sets the mock callout mode.com/foo/bar'.callEchoString('Hello World!'). String requestName. This is similar to how the AJAX Toolkit and . respElement). sample. } } This is the method that makes a Web service callout. instead of starting with a WSDL. The generated Apex has two variables. both named a_x. and Axis. You can use these HTTP classes to integrate to REST-based services. an x character is prepended to the generated Apex variable name. an x character is appended to the generated Apex variable name. which is not allowed in Apex. If an element name contains a character that is not allowed in an Apex variable name. More than one loopback connection to Salesforce domains is not allowed. Circular references in Apex classes are not allowed. a_ and a_x.Invoking Callouts Using Apex Invoking HTTP Callouts Understanding Runtime Events The following checks are performed when Apex code is making a callout to an external service. 251 . • Debugging Classes Generated from WSDL Files Salesforce tests code with SOAP API. see SOAP API and SOAP Headers for Apex on page 624. To allow an endpoint to be accessed. Invoking HTTP Callouts Apex provides several built-in classes to work with HTTP services and create HTTP requests like GET. You must manually edit the Apex and change one of the variable names. The class will not compile. see HTTP (RESTful) Services Classes. the Force. . By using the HTTP classes. The following rules apply when generating Apex variable names from a WSDL file: • • • • If the first character of an element name is not alphabetic. see Callout Limits and Limitations on page 254. the first character is replaced with an underscore (_) character and the second one is replaced with an x character. If you use other tools. • • • • • For information on the timeout limits when making an HTTP request or a Web services call. If the last character of an element name is not allowed in an Apex variable name. the character is replaced with an underscore (_) character. you take on more responsibility for handling the construction of the SOAP message for the request and response. Understanding Unsupported Characters in Variable Names A WSDL file can include an element name that is not allowed in an Apex variable name. You can use the debugging header to return the XML in request and response SOAP messages to help you diagnose problems. If an element name contains two characters in a row that are not allowed in an Apex variable name. and DELETE. To prevent database connections from being held up.com Toolkit for Google Data APIs makes extensive use of HTTP callouts. For more information. For more information and samples. Suppose you have an operation that takes two parameters. Also. you might encounter issues. POST. PUT. it should be registered in Your Name > Setup > Security > Remote Site Settings. This avoids generating a variable name with two successive underscores.NET. no transactions can be open. They also allow you to integrate to SOAP-based web services as an alternate option to generating Apex code from a WSDL. Generate a certificate. Enter a descriptive label for the Salesforce certificate. 2. Note: Once you save a Salesforce certificate. Selecting 1024 generates a certificate using 1024-bit keys and is valid for one year. Before any Apex callout can call an external site. not include spaces. 3.Invoking Callouts Using Apex Using Certificates Using Certificates You can use two-way SSL authentication by sending a certificate generated in Salesforce or signed by a certificate authority (CA) with your callout. Select a Key Size for your generated certificate and keys.developerforce. see wiki. that site must be registered in the Remote Site Settings page. Selecting 2048 generates a certificate using 2048-bit keys and is valid for two years.mycompany. Select either Create Self-Signed Certificate or Create CA-Signed Certificate. 252 .php/Making_Authenticated_Web_Service_Callouts_Using_Two-Way_SSL. If you are connecting to another application used within your organization. We recommend that you use the default key size of 2048 for security reasons. Configure the remote site settings for the callout. These fields are joined together to generate a unique certificate. 4. configure your Web or application server to request a client certificate. This process depends on the type of Web or application server you use. This name is automatically populated based on the certificate label you enter. and not contain two consecutive underscores.com Web services API or Apex. Integrate the certificate with your code. 3. 5.com/index. This is generally of the form: http://www. Go to Your Name > Setup > Security Controls > Certificate and Key Management. It must begin with a letter. you must also enter the following information. This enhances security as the target of the callout receives the certificate and can use it to authenticate the request against its keystore. you can’t change the key size. 2. 6. If you are connecting to a third-party and you are using a self-signed certificate. based on what kind of certificate your external website accepts. 4.com. not end with an underscore. or the callout fails. See Using Certificates with SOAP Services and Using Certificates with HTTP Requests. and must be unique in your organization. Enter the Unique Name. Field Common Name Description The fully qualified domain name of the company requesting the signed certificate. This name can contain only underscores and alphanumeric characters. You can’t change the type of a certificate after you’ve created it. For an example of how to set up two-way SSL with Apache Tomcat. If you’re creating a CA-signed certificate. This name is used primarily by administrators when viewing certificates. Use the Unique Name when referring to the certificate using the Force. Generating Certificates You can use a self-signed certificate generated in Salesforce or a certificate signed by a certificate authority (CA). To enable two-way SSL authentication for a callout: 1. share the Salesforce certificate with them so that they can add the certificate to their keystore. To generate a certificate for a callout: 1. The branch of your company using the certificate. The following example illustrates the last step of the previous procedure and works with the sample WSDL file in Understanding the Generated Code. and assign a value to a clientCertName_x variable on an instance of the stub class.EchoString(input). and assign it to the clientCert_x variable on the stub. 3. When you use a Salesforce certificate. Generate Apex classes from the WSDL for the Web service. For the United States. the value is US. stub. This example assumes that you previously generated a certificate with a Unique Name of DocSampleCert. you must upload the signed certificate before you can use it. the certificate and corresponding keys are automatically generated. A two-letter code indicating the country where the company resides. City State Country Code 7. Receive the WSDL for the Web service from the third party or generate it from the application you want to connect to. 253 . such as marketing or accounting.DocSamplePort stub = new docSample. Encode your client certificate key in base64. Click Save. To integrate the certificate with your Apex: 1. 2. See “Uploading Certificate Authority (CA)-Signed Certificates” in the Salesforce online help. Either the legal name of your company.clientCertName_x = 'DocSampleCert'. There is a legacy process for using a certificate obtained from a third party for your organization. or your legal name. This is inherently less secure than using a Salesforce certificate because it does not follow security best practices for protecting private keys. docSample. After you create a CA-signed certificate. The state where the company resides.DocSamplePort(). you can use it to support two-way authentication for a callout to a SOAP Web service. the private key is not shared outside Salesforce. String input = 'This is the input string'. The city where the company resides. Edit the Apex classes. The value must match the Unique Name of the certificate you generated using Your Name > Setup > Security Controls > Certificate and Key Management. The generated Apex classes include a stub for calling the third-party Web service represented by the WSDL document. String output = stub. After you successfully save a Salesforce certificate. Using Certificates with SOAP Services After you have generated a certificate in Salesforce.Invoking Callouts Using Apex Using Certificates with SOAP Services Field Email Address Company Department Description The email address associated with this certificate. See SOAP Services: Defining a Class from a WSDL Document. asynchronous Apex (such as future methods and batch Apex jobs). scheduled Apex. String input = 'This is the input string'. See the following examples for how to set custom timeouts for Web services or HTTP callouts. docSample. The maximum cumulative timeout for callouts by a single Apex transaction is 120 seconds. • • 254 . stub. you can use it to support two-way authentication for a callout to an HTTP request.DocSamplePort stub = new docSample. Note the Unique Name of the certificate. The default timeout is 10 seconds.EchoString(input). In your Apex. Using Certificates with HTTP Requests After you have generated a certificate in Salesforce. This time is additive across all callouts invoked by the Apex transaction.DocSamplePort(). This example assumes that you previously generated a certificate with a Unique Name of DocSampleCert. The minimum is 1 millisecond and the maximum is 120 seconds seconds. You can make callouts before performing these types of operations. 2. The value used for the argument for this method must match the Unique Name of the certificate that you generated in the previous step. req. The following example illustrates the legacy process and works with the sample WSDL file in Understanding the Generated Code on page 246. A custom timeout can be defined for each callout. • • A single Apex transaction can make a maximum of 10 callouts to an HTTP request or an API call. Generate a certificate. Callout Limits and Limitations The following limits and limitations apply when Apex code makes a callout to an HTTP request or a Web services call. // Password for the keystore stub. use the setClientCertificateName method of the HttpRequest class. You must use a certificate obtained from a third party for your organization if you use the legacy process. The following example illustrates the last step of the previous procedure. Things that result in pending operations are DML statements. or sending email. String output = stub.clientCertPasswd_x = 'passwd'.setClientCertificateName('DocSampleCert').Invoking Callouts Using Apex Using Certificates with HTTP Requests Note: Do not use a client certificate generated from Your Name > Setup > Develop > API > Generate Client Certificate. The Web services call can be a SOAP API call or any external Web services call. HttpRequest req = new HttpRequest(). To integrate the certificate with your Apex: 1. You can’t make a callout when there are pending operations in the same transaction.clientCert_x = 'MIIGlgIBAzCCBlAGCSqGSIb3DQEHAaCCBkEEggY9MIIGOTCCAe4GCSqGSIb3DQEHAaCCAd8EggHb'+ 'MIIB1zCCAdMGCyqGSIb3DQEMCgECoIIBgjCCAX4wKAYKKoZIhvcNAQwBAzAaBBSaUMlXnxjzpfdu'+ '6YFwZgJFMklDWFyvCnQeuZpN2E+Rb4rf9MkJ6FsmPDA9MCEwCQYFKw4DAhoFAAQU4ZKBfaXcN45w'+ '9hYm215CcA4n4d0EFJL8jr68wwKwFsVckbjyBz/zYHO6AgIEAA=='. // timeout in milliseconds The following is an example of setting a custom timeout for HTTP callouts: HttpRequest req = new HttpRequest().DocSamplePort stub = new docSample. // timeout in milliseconds 255 . docSample.setTimeout(2000).timeout_x = 2000.DocSamplePort(). Set the timeout value in milliseconds by assigning a value to the special timeout_x variable on the stub.Invoking Callouts Using Apex Callout Limits and Limitations Setting Callout Timeouts The following example sets a custom timeout for Web services callouts. The example works with the sample WSDL file and the generated DocSamplePort class described in Understanding the Generated Code on page 246. stub. req. sObjects. 256 . See SOAP API and SOAP Headers for Apex on page 624 in the Appendices section. • • • • Apex Data Manipulation Language (DML) Operations Apex Standard Classes and Methods Apex Classes Apex Interfaces The Apex reference contains information about the Apex language.. collections. and other parts of Apex Apex classes—prebuilt classes available for your use Apex interfaces—interfaces you can implement In addition. • • • • Data manipulation language (DML) operations—used to manipulate data in the database Standard classes and methods—available for primitive data types. SOAP API methods and objects are available for Apex..Chapter 13 Reference In this chapter . catch blocks). Your application can then inspect the rejected records and possibly retry the operation. the remainder of the DML operation can still succeed. You can execute DML operations using two different forms: • Apex DML statements. However. Use DML database methods if you want to allow partial success of a bulk DML operation—if a record fails. This behavior is similar to the way exceptions are handled in most database procedural languages. such as: insert SObject[] • Apex DML database methods. Instead. delete.Reference Apex Data Manipulation Language (DML) Operations Apex Data Manipulation Language (DML) Operations Use data manipulation language (DML) operations to insert. the current user's sharing rules are taken into account. such as: Database. position in the role hierarchy. merge is only available as an Apex DML statement. when a DML operation is called in a class defined with the with sharing keywords.SaveResult[] result = Database. field-level security. 1 2 convertLead is only available as a database method. The different DML operation forms enable different types of exception processing: • Use DML statements if you want any error that occurs during bulk DML processing to be thrown as an Apex exception that immediately interrupts control flow (by using try.0 and higher produce a runtime error if you assign a String value that is too long for the field. your code can use the appropriate results array to judge success or failure. String Field Truncation and API Version Apex classes and triggers saved (compiled) using API version 15. . and sharing rules. organization-wide defaults. similar to DML statements. . Note that DML database methods also include a syntax that supports thrown exceptions.Insert(SObject[]) While most DML operations are available in either form. you can write code that never throws DML exception errors. ignoring the current user's permissions. For more information. and restore data in a database. 257 . When using this form. see Using the with sharing or without sharing Keywords on page 124. some exist only in one form or the other. update. • The following Apex DML operations are available: • • • • • • • convertLead1 delete insert merge2 undelete update upsert System Context and Sharing Rules Most DML operations execute in system context. contact. • • • Basic Steps for Converting Leads Converting leads involves the following basic steps: 258 . and opportunity fields. Boolean opt_allOrNone) The optional opt_allOrNone parameter specifies whether the operation allows partial success. the remainder of the DML operation can still succeed. ensure that field values are already defined. the default record type of the new owner is assigned to records created during lead conversion. and opportunity. If you specify false for this parameter and a record fails. The only exception is if you specify setOverwriteLeadSource on the LeadConvert object to true. if a custom lead field is mapped to a contact picklist field. and opportunity records in their news feed. see the Salesforce online help. For more information about record types. and users that were subscribed to the lead aren’t automatically subscribed to the generated records. contact. A user can subscribe to a record so that changes to the record are displayed in the news feed on the user's home page. To resolve the error.Reference ConvertLead Operation ConvertLead Operation The convertLead DML operation converts a lead into an account and contact. consider the following rules and guidelines: • Field mappings: The system automatically maps standard lead fields to standard account. the lead conversion will fail if the data in a custom lead field isn't supported in the mapped custom contact field.convertLead(LeadConvert leadToConvert. the lead value must be explicitly defined as a contact picklist value.convertLead(LeadConvert[] leadsToConvert. Picklist values: The system assigns the default picklist values for the account. as well as (optionally) an opportunity. This method returns a result object that can be used to verify which records succeeded. For more information about field mappings. Otherwise the lead won’t be converted. They must have automatic subscriptions enabled to see changes to the account. your Salesforce administrator can specify how they map to custom account. Rules and Guidelines When converting leads. Note: convertLead is only available as a database method. Record types: If the organization uses record types. contact. For custom lead fields. which failed. Users must enable automatic subscriptions by selecting the Automatically follow records that I create checkbox in User Name > Setup > My Chatter Settings > My Feeds to subscribe to records they create. add the values to the default record type of the user converting the lead. contact. in which case the LeadSource field in the target contact object is overwritten with the contents of the LeadSource field in the source LeadConvert object. If the desired lead source values are not available. see the Salesforce online help. If your organization uses record types. contact. and why. and opportunity fields. the owner of the generated records. Automatic feed subscriptions: When you convert a lead into a new account. Boolean opt_allOrNone) LeadConvertResult[] Database. blank values are replaced with the default picklist values of the new record owner. we recommend enabling validation and triggers from lead convert in your organization’s lead settings. the lead owner is unsubscribed from the lead account. • Merged fields: If data is merged into existing account and contact objects. The lead owner. unless they have automatic subscriptions enabled in their Chatter feed settings. Database Method Syntax • • LeadConvertResult Database. To prevent the error. For example. only empty fields in the target object are overwritten—existing data (including IDs) are not overwritten. and opportunity when mapping any standard lead picklist fields that are blank. If you haven’t enabled validation and triggers from lead convert. The default record type of the user converting the lead determines the lead source values available during conversion. This is a useful way to stay up-to-date with changes to records in Salesforce. Optionally. isOverWriteLeadSource isSendNotificationEmail Boolean ID ID Void setAccountId 259 . a new account is created. as in the following example: SELECT Id. Optionally. Get the name of the opportunity to create. Indicates whether the LeadSource field on the target Contact object is overwritten with the contents of the LeadSource field in the source Lead object (true). Name FROM Contact WHERE FirstName='FirstName' AND LastName='LastName' AND AccountId = '001. Gets the ID of the contact into which the lead will be merged.' 4. Your application determines the IDs of any lead(s) to be converted. 7. including person accounts. The application can use SOQL to search for contacts that match the lead contact name. your application determines the IDs of any account(s) into which to merge the lead. Get the ID of the person to own any newly created account. LeadConvert Object Methods The convertLead database method accepts up to 100 LeadConvert objects. as in the following example: SELECT Id. the default). A LeadConvert object supports the following methods: Name getAccountId getContactId getConvertedStatus getLeadID getOpportunityName getOwnerID isDoNotCreateOpportunity Arguments Return Type Description ID ID String ID String ID Boolean Boolean Gets the ID of the account into which the lead will be merged. if setAccountID is specified. 6. Indicates whether a notification email is sent to the owner specified by setOwnerId (true) or not (false. and then selects a value for the converted status. Name FROM Account WHERE Name='CompanyNameOfLeadBeingMerged' 3.Reference ConvertLead Operation 1. the owner must be specified. the default) or not (true). Even if you are specifying an existing account or contact. contact. the default). Optionally. 8.. Optionally. or not (false. FROM LeadStatus WHERE IsConverted='1'). The application calls convertLead. This value is required only when updating an existing account. 5. Sets the ID of the account into which the lead will be merged... Your application can use SOQL to search for accounts that match the lead name.. Get the lead status value for a converted lead Get the ID of the lead to convert. you must still specify an owner. 2. Otherwise. This is because accounts and contacts cannot be owned by a queue. Indicates whether an Opportunity is created during lead conversion (false. your application determines the IDs of the contact or contacts into which to merge the lead. and opportunity. The application queries the LeadSource table to obtain all of the possible converted status options (SELECT . the application determines whether opportunities should be created from the leads. when converting leads owned by a queue. The application iterates through the returned result or results and examines each LeadConvertResult object to determine whether conversion succeeded for each lead. and setAccountId must be specified). Specifies whether to create an opportunity during lead conversion. Specifies whether to overwrite the LeadSource field on the target contact object with the contents of the LeadSource field in the source lead object. If the application does not specify this value. Set this flag to true only if you do not want to create an opportunity from the lead. contact. you must also specify setContactId for the target contact. This value is required only when updating an existing contact. otherwise.Reference ConvertLead Operation Name setContactId Arguments ID ID Return Type Description Void Sets the ID of the contact into which the lead will be merged (this contact must be associated with the account specified with setAccountId. the owner of the new object will be the owner of the lead. If setDoNotCreateOpportunity is true. the ownerId field is not overwritten in an existing account or contact. to not overwrite the field. and opportunity. This method is not applicable when merging with existing objects—if setOwnerId is specified. If no name is specified. in which case only the LeadSource field is overwritten). to not send email. This field is required. Sets the ID of the lead to convert. The default value is false. Specifies whether to send a notification email to the owner specified by setOwnerId. The maximum length of this field is 80 characters. that is. Each element in the LeadConvertResult array corresponds to the SObject array passed as the SObject[] parameter in the convertLead database 260 . Important: If you are converting a lead into a person account. The default value is false. do not specify setContactId or an error will result. setConvertedStatus String Status Void Sets the lead status value for a converted lead. Specify only setAccountId of the person account. this value defaults to the company name of the lead. no Opportunity is created and this field must be left blank. The contact name and other existing data are not overwritten (unless setOverwriteLeadSource is set to true. then the application creates a new contact that is implicitly associated with the account. an error is returned. setDoNotCreateOpportunity Boolean Void CreateOpportunity setLeadId setOpportunityName ID ID Void String OppName Void setOverwriteLeadSource Boolean Void O v e r w r i t e L e a d S o u r c e setOwnerId ID ID Void setSendNotificationEmail Boolean SendEmail Void LeadConvertResult Object An array of LeadConvertResult objects is returned with the convertLead database method. If you specify this as true. If setContactID is specified. Specifies the ID of the person to own any newly created account. Sets the name of the opportunity to create. This field is required. The default value is false: opportunities are created by default. ID ID Boolean The ID of the converted lead The ID of the new opportunity. such as individual accounts or contacts. DML Statement Syntax delete sObject | Record. A LeadConvertResult object has the following methods: Name getAccountId Type ID Description The ID of the new account (if a new account was specified) or the ID of the account specified when convertLead was invoked The ID of the new contact (if a new contact was specified) or the ID of the contact specified when convertLead was invoked getContactId ID getErrors Database. that is.Reference Delete Operation method. lc.LeadConvertResult lcr = Database. If only one SObject is passed in.Error [] objects providing the error code and description. Delete Operation The delete DML operation deletes one or more existing sObject records. LeadStatus convertStatus = [SELECT Id. System.LeadConvert(). the first element in the LeadConvertResult array matches the first element passed in the SObject array. and so on. delete is analogous to the delete() statement in the SOAP API.MasterLabel). from your organization’s data.setConvertedStatus(convertStatus. false otherwise getLeadId getOpportunityId isSuccess Database Method Example Lead myLead = new Lead(LastName = 'Fry'.Delete((sObject recordToDelete | RecordID ID).Delete((sObject[] recordsToDelete | RecordIDs LIST<>IDs{}). the second element corresponds with the second element. Company='Fry And Sons'). Database.assert(lcr.setLeadId(myLead. see Database Error Object Methods on page 389. MasterLabel FROM LeadStatus WHERE IsConverted=true LIMIT 1].id).convertLead(lc). an array of one or more database error []Database. if one was created when convertLead was invoked A Boolean value that is set to true if the DML operation was successful for this object.ID Database Method Syntax • • DeleteResult Database. lc.isSuccess()). Database. insert myLead. the LeadConvertResults array contains a single element.Error If an error occurred. For more information. Boolean opt_allOrNone) 261 .LeadConvert lc = new database. Boolean opt_allOrNone) DeleteResult[] Database. false otherwise getId isSuccess Boolean DML Statement Example The following example deletes all accounts that are named 'DotCom': Account[] doomedAccts = [SELECT Id. delete supports cascading deletions. You can pass a maximum of 10. if a particular child record is not deletable or is currently being used. then the delete operation on the parent case record fails. the DeleteResults array contains a single element. which failed.Reference Delete Operation The optional opt_allOrNone parameter specifies whether the operation allows partial success. the deletable property of the sObject must be set to true. ID The ID of the sObject you were trying to delete. A Boolean value that is set to true if the DML operation was successful for this object. If you specify false for this parameter and a record fails. If this field contains a value. If this field is empty. consider the following rules and guidelines: • To ensure referential integrity. CaseHistory. If only one sObject is passed in. the first element in the DeleteResult array matches the first element passed in the sObject array.Error If an error occurred. • • Certain sObjects can't be deleted. the second element corresponds with the second element. the operation was not successful for that object. and so on. and why.DeleteResult objects is returned with the delete database method. see Bulk DML Exception Handling on page 278. the remainder of the DML operation can still succeed. see Database Error Object Methods on page 389. If you delete a parent object. A Database. 262 . try { delete doomedAccts. However. Also. This method returns a result object that can be used to verify which records succeeded. the object was successfully deleted. } catch (DmlException e) { // Process exception here } Note: For more information on processing DmlExceptions. that is. DeleteResult Object An array of Database. Apex automatically deletes any CaseComment. if you delete a case record.DeleteResult object has the following methods: Name getErrors Type Description Database. Name FROM Account WHERE Name = 'DotCom']. and CaseSolution records associated with that case. as long as each child record can be deleted. To delete an sObject record.000 sObject records to a single delete method. you delete its children automatically. an array of one or more database error objects [] providing the error code and description. Rules and Guidelines When deleting sObject records. For example. Each element in the DeleteResult array corresponds to the sObject array passed as the sObject[] parameter in the delete database method. see sObjects That Do Not Support DML Operations on page 275. For more information. Reference Insert Operation Database Method Example The following example deletes an account named 'DotCom': Account[] doomedAccts = [SELECT Id.SaveResult[] MySaveResult = Database. Lead l = new Lead(Company='ABC'.DeleteResult[] DR_Dels = Database. 263 . such as assignment rule information or rollback behavior when errors occur during record insertions. dmo. This method returns a result object that can be used to verify which records succeeded. DML Statement Syntax insert sObject insert sObject[] Database Method Syntax • • SaveResult Database. Database. l. For more information. to your organization’s data.Insert(MyAccounts. the remainder of the DML operation can still succeed. The optional opt_DMLOptions parameter specifies additional data for the transaction.DMLOptions().UseDefaultRule= true. LastName='Smith'). For example: //AssignmentRuleHeader //UseDefaultRule Database.insert(sObject[] recordsToInsert. which failed. insert is analogous to the INSERT statement in SQL. To create an sObject record. You must supply a non-null value for all required fields. If you specify false for this parameter and a record fails. the createable property of the sObject must be set to true. Boolean opt_allOrNone | database. Boolean opt_allOrNone | database. and why.DMLOptions dmo = new database. see Database DMLOptions Properties on page 386.insert(sObject recordToInsert. false). Rules and Guidelines When inserting sObject records.delete(doomedAccts). Name FROM Account WHERE Name = 'DotCom'].DMLOptions opt_DMLOptions) SaveResult[] Database. Insert Operation The insert DML operation adds one or more sObjects. such as individual accounts or contacts. insert l.setOptions(dmo). For example: Database.AssignmentRuleHeader.DMLOptions opt_DMLOptions) The optional opt_allOrNone parameter specifies whether the operation allows partial success. consider the following rules and guidelines: • • Certain sObjects cannot be created. However. The insert statement can only set the foreign key ID of related sObject records. See Lists for more information. if inserting a new contact. } catch (DmlException e) { // Process exception here } 264 . inserting duplicate sObject records results in an error. an array of one or more database error objects providing the error code and description. If this field contains a value. Inserting a record that already has an ID—and therefore already exists in your organization's data—produces an error. the operation was not successful for that object. and so on. try { insert newAcct. getId ID isSuccess Boolean DML Statement Example The following example inserts an account named 'Acme': Account newAcct = new Account(name = 'Acme'). Fields on related records cannot be updated with insert. inserting CollaborationGroup sObjects with the same name results in an error because CollaborationGroup records must have unique names. If this field is empty. The ID of the sObject you were trying to insert or update. The insert statement is not supported with some sObjects. see Database Error Object Methods on page 389. you cannot change the account's name without updating the account itself with a separate DML call. For example. See sObjects That Do Not Support DML Operations on page 275. The insert statement automatically sets the ID value of all new sObject records. A SaveResult object has the following methods: Name getErrors Type Database. the SaveResult for those entries is marked with an error similar to the following: Maximum number of duplicate updates in one batch (5 allowed). If there are duplicates. Attempt to update Id more than once in this API call: number_of_attempts. For more information. false otherwise. the first element in the SaveResult array matches the first element passed in the sObject array. you can specify the contact's related account record by setting the value of the AccountId field. This operation checks each batch of records for duplicate ID values.Reference Insert Operation • • • • • • You can pass a maximum of 10.Error [] Description If an error occurred. the SaveResults array contains a single element. Each element in the SaveResult array corresponds to the sObject array passed as the sObject[] parameter in the database method.000 sObject records to a single insert method. the object was successfully inserted or updated. A Boolean that is set to true if the DML operation was successful for this object. that is. For example. If only one sObject is passed in. For the sixth and all additional duplicate IDs. the second element corresponds with the second element. For some sObjects that have fields with unique constraints. SaveResult Object An array of SaveResult objects is returned with the insert and update database methods. the first five are processed. Database Method Example The following example inserts an account named 'Acme': Account a = new Account(name = 'Acme'). the array index of the parent must be lower than the child’s index. The following example shows how to create an opportunity with a parent account using the same insert statement.addDays(7).SaveResult[] lsr = Database. 265 . Database.insert(new Account[]{a. This sample requires an external ID text field on Account called MyExtID. You can create related records that are up to 10 levels deep. MyExtID__c. Next. Opportunity newOpportunity = new Opportunity( Name='OpportunityWithAccountInsert'. and optionally other fields. This sObject must have the required fields (and optionally other fields) set in addition to the external ID field. Create another parent sObject to be passed to the insert statement. then creates two Account objects. that is. The first account is only for the foreign key relationship. This sObject has only the external ID field defined and no other fields set. the sample checks the results and writes the IDs of the created records to the debug log. Both accounts have the external ID field.Error err = sr. The Database. The parent sObject must precede the child sObject in the array. such as a master-detail or lookup relationship.insert by passing it an array of sObjects. see Bulk DML Exception Handling on page 278. The parent and child records are records related through a predefined relationship. // Used only for foreign key reference // and doesn't contain any other fields. } Creating Parent and Child Records in a Single Statement Using Foreign Keys You can use external ID fields as foreign keys to create parent and child records of different sObject types in a single step instead of creating the parent record first. StageName='Prospecting'.getErrors()[0]. // Iterate through the Save Results for(Database. set.insert statement creates the opportunity with its parent account in a single step.Reference Insert Operation Note: For more information on processing DmlExceptions. CloseDate=dt). // Create the parent reference. the related records created in a single call must have different sObject types. Create the parent reference sObject used only for setting the parent foreign key reference on the child sObject. new Account(Name = 'Acme')}. Call insert by passing it an array of sObjects to create. see Creating Records for Different Object Types in the SOAP API Developer's Guide.today(). the sample calls Database. false). Account accountReference = new Account( MyExtID__c='SAP111111'). The first element in the array is the parent sObject and the second is the opportunity sObject. or the first error if record creation fails. querying its ID. dt = dt. public class ParentChildSample { public static void InsertParentChild() { Date dt = Date. and the second is for the account creation and has the account fields set. Set the foreign key field of the child sObject to the parent reference sObject you just created. and then creating the child record. To do this: • • • • • Create the child sObject and populate its required fields.isSuccess()) Database. The example creates an Opportunity sObject and populates some of its fields. Also. Finally.SaveResult sr:lsr){ if(!sr. For more information. i++) { if (results[i]. Note: This DML operation does not have a matching database system method.debug('Successfully created ID: ' + results[i]. System.debug('Error: could not create sobject ' + 'for array element ' + i + '. newOpportunity }). You can pass a master record and up to two additional sObject records to a single merge method.insert(new SObject[] { parentAccount.Account = accountReference. // Create the account and the opportunity. For more information on merging leads. Rules and Guidelines When merging sObject records.isSuccess()) { System. i < results. or as a list of two sObject records or IDs.getErrors()[0]. Database. // Used for the insert.Reference Merge Statement newOpportunity. 266 . deleting the others. consider the following rules and guidelines: • • Only leads. // Check results.getId()). You can pass these other records into the merge statement as a single sObject record or ID. } } } } Merge Statement The merge statement merges up to three records of the same sObject type into one of the records. and accounts can be merged. contacts. // Create the Account object to insert.'). The second parameter represents the one or two other records that should be merged and then deleted.getMessage() + '\n').SaveResult[] results = Database. contacts and accounts. and re-parenting any related records. see the Salesforce online help.size(). Account parentAccount = new Account( Name='Hallie'. Syntax merge sObject sObject merge sObject sObject[] merge sObject ID merge sObject ID[] The first parameter represents the master record into which the other records are to be merged. See sObjects That Do Not Support DML Operations on page 275.debug(' The error reported was: ' + results[i]. // Same as above but has Name field. MyExtID__c='SAP111111'). for (Integer i = 0. } else { System. ' LIMIT 1]. This method returns a result object that can be used to verify which records succeeded.new Account(name='Acme')}. } catch (DmlException e) { // Process exception here } Note: For more information on processing DmlExceptions. see Bulk DML Exception Handling on page 278. try { merge masterAcct mergeAcct. undelete is analogous to the UNDELETE statement in SQL. Account masterAcct = [SELECT Id. and why. Undelete Operation The undelete DML operation restores one or more existing sObject records. with some exceptions Tags An article's categories.Reference Undelete Operation Example The following example merges two accounts named 'Acme Inc.Undelete((sObject[] recordsToUndelete | RecordIDs LIST<>IDs{}). Name FROM Account WHERE Name = 'Acme' LIMIT 1]. DML Statement Syntax undelete sObject | Record. Boolean opt_allOrNone) The optional opt_allOrNone parameter specifies whether the operation allows partial success. Name FROM Account WHERE Name = 'Acme Inc.'). publication state. such as individual accounts or contacts.ID undelete sObject[] | LIST<>ID[] Database Method Syntax • • UndeleteResult Database. If you specify false for this parameter and a record fails. the remainder of the DML operation can still succeed. undelete restores the record associations for the following types of relationships: ◊ ◊ ◊ ◊ ◊ ◊ ◊ ◊ ◊ ◊ Parent accounts (as specified in the Parent Account field on an account) Parent cases (as specified in the Parent Case field on a case) Master solutions for translated solutions (as specified in the Master Solution field on a solution) Managers of contacts (as specified in the Reports To field on a contact) Products related to assets (as specified in the Product field on an asset) Opportunities related to quotes (as specified in the Opportunity field on a quote) All custom lookup relationships Relationship group members on accounts and relationship groups.Undelete((sObject recordToUndelete | RecordID ID). consider the following rules and guidelines: • To ensure referential integrity. Account mergeAcct = [SELECT Id.' and 'Acme' into a single record: List<Account> ls = new List<Account>{new Account(name='Acme Inc. which failed. Rules and Guidelines When undeleting sObject records. and assignments 267 . insert ls. Boolean opt_allOrNone) UndeleteResult[] Database. from your organization’s Recycle Bin. but the child objects will have been re-parented. try { undelete savedAccts. Undelete is not supported with some sObjects. which cannot be undone. A Boolean value that is set to true if the DML operation was successful for this object. The ID of the sObject you were trying to undelete.Reference Undelete Operation Note: Salesforce only restores lookup relationships that have not been replaced.000 sObject records to a single undelete method. The ALL ROWS keyword queries all rows for both top level and aggregate relationships. the operation was not successful for that object. • • • • • Certain sObjects can't be undeleted. the UndeleteResults array contains a single element. For more information. You can undelete records that were deleted as the result of a merge. Use the ALL ROWS parameters with a SOQL query to identify deleted records. You can pass a maximum of 10. insert(new Contact(LastName='Carter'. insert(a). If only one sObject is passed in. UndeleteResult Object An array of Database. If this field contains a value. that asset-product relationship is not restored. For example. Each element in the UndeleteResult array corresponds to the sObject array passed as the sObject[] parameter in the undelete database method. If this field is empty. an array of one or more database error objects providing the error code and description. Name FROM Account WHERE Name = 'Trump' ALL ROWS]. check that the undeletable property of the sObject is set to true. the first element in the UndeleteResult array matches the first element passed in the sObject array. false otherwise getId ID isSuccess Boolean DML Statement Example The following example undeletes an account named 'Trump'. To verify if an sObject record can be undeleted. Account[] savedAccts = [SELECT Id. See sObjects That Do Not Support DML Operations on page 275. An undeleteResult object has the following methods: Name getErrors Type Database. see Database Error Object Methods on page 389. that is. Account a = new Account(Name='AC1'). including deleted records and archived activities.Id)). if an asset is related to a different product prior to the original product record being undeleted. the object was successfully undeleted. the second element corresponds with the second element. See Querying All Records with a SOQL Statement on page 73.UndeleteResult objects is returned with the undelete database method.AccountId=a. and so on.Error [] Description If an error occurred. including records deleted as a result of a merge. } catch (DmlException e) { 268 . Boolean opt_allOrNone | database.UndeleteResult[] UDR_Dels = Database. When updating required fields you must supply a non-null value. the updateable property of the sObject must be set to true. such as individual accounts or contactsinvoice statements. the remainder of the DML operation can still succeed. For more information. Boolean opt_allOrNone | database. i< 10. see Database DMLOptions Properties on page 386. 269 . update is analogous to the UPDATE statement in SQL.Reference Update Operation // Process exception here } Note: For more information on processing DmlExceptions. for(integer i =0. Database Method Example The following example undeletes an account named 'Trump'. in your organization’s data.size()>0){ // Process any errors here } } } Update Operation The update DML operation modifies one or more existing sObject records. consider the following rules and guidelines: • • Certain sObjects cannot be updated. This method returns a result object that can be used to verify which records succeeded. public class DmlTest2 { public void undeleteExample() { Account[] SavedAccts = [SELECT Id.DMLOptions opt_DMLOptions) UpdateResult[] Update(sObject[] recordsToUpdate[].getErrors().undelete(SavedAccts). including deleted records and archived activities. such as assignment rule information or rollback behavior when errors occur during record insertions. see Bulk DML Exception Handling on page 278. Database. DML Statement Syntax update sObject update sObject[] Database Method Syntax • • UpdateResult Update(sObject recordToUpdate. The ALL ROWS keyword queries all rows for both top level and aggregate relationships. i++) if(UDR_Dels[i].DMLOptions opt_DMLOptions) The optional opt_allOrNone parameter specifies whether the operation allows partial success. Rules and Guidelines When updating sObject records. which failed. To update an sObject record. and why. The optional opt_DMLOptions parameter specifies additional data for the transaction. Name FROM Account WHERE Name = 'Trump' ALL ROWS]. If you specify false for this parameter and a record fails. // This updates the account name • Update is not supported with some sObjects. The update statement automatically modifies the values of certain fields such as LastModifiedDate. the first five are processed. Apex allows you to change field values to null without updating the fieldsToNull array on the sObject record. You can pass a maximum of 10. If this field is empty.000 sObject records to a single update method. This operation checks each batch of records for duplicate ID values. // This only changes the contact's last name update c. and SystemModstamp.Account. The ID of an updated sObject record cannot be modified. that is. If this field contains a value. A single update statement can only modify one type of sObject at a time. LastModifiedById. an array of one or more database error objects providing the error code and description. the SaveResult for those entries is marked with an error similar to the following: Maximum number of duplicate updates in one batch (5 allowed). if updating an account field through an existing contact that has also been modified. the second element corresponds with the second element.com'. the object was successfully inserted or updated.Account. The API requires an update to this array due to the inconsistent handling of null values by many SOAP providers.Name = 'salesforce. If there are duplicates. see Database Error Object Methods on page 389. // To update the database. A SaveResult object has the following methods: Name getErrors Type Database. the first element in the SaveResult array matches the first element passed in the sObject array. See sObjects That Do Not Support DML Operations on page 275. c. the two types of records must be // updated separately update c. the SaveResults array contains a single element. Each element in the SaveResult array corresponds to the sObject array passed as the sObject[] parameter in the database method.LastName = 'Roth'. two update statements are required: // Use a SOQL query to access data for a contact Contact c = [SELECT Account. and so on.com platform.Reference Update Operation • • • • • • Unlike the SOAP API. For more information.Name FROM Contact WHERE LastName = 'Carter' LIMIT 1]. If only one sObject is passed in. The ID of the sObject you were trying to insert or update. You cannot explicitly specify these values in your Apex.Error [] Description If an error occurred. Because Apex runs solely on the Force. this workaround is unnecessary. getId ID 270 . Attempt to update Id more than once in this API call: number_of_attempts. but related record IDs can. // Now we can change fields for both the contact and its // associated account c. For the sixth and all additional duplicate IDs. For example. SaveResult Object An array of SaveResult objects is returned with the insert and update database methods. the operation was not successful for that object. Additionally. Database Method Example The following example updates the BillingCity field on a single account named 'Acme': Account a = new Account(Name='Acme2'). Account myAcct = [SELECT Id. } catch (DmlException e) { // Process exception here } Note: For more information on processing DmlExceptions.Reference Upsert Operation Name isSuccess Type Boolean Description A Boolean that is set to true if the DML operation was successful for this object. This custom field must be created with the External Id attribute selected.Id]. insert(a). DML Statement Syntax upsert sObject opt_external_id upsert sObject[] opt_external_id opt_external_id is an optional variable that specifies the custom field that should be used to match records that already exist in your organization's data. myAcct. Account myAcct = [SELECT Id. 271 .getErrors()) { // process any errors here } Upsert Operation The upsert DML operation creates new sObject records and updates existing sObject records within a single statement. false otherwise.BillingCity = 'San Francisco'. using an optional custom field to determine the presence of existing objects.Error err: SR. BillingCity FROM Account WHERE Id = :a. Name. myAcct. BillingCity FROM Account WHERE Id = :a. try { update myAcct. for(Database.Id]. DML Statement Example The following example updates the BillingCity field on a single account named 'Acme': Account a = new Account(Name='Acme2'). the context user must have the “View All” object-level permission for the target object or the “View All Data” permission so that upsert does not accidentally insert a duplicate record. if the field does not have the Unique attribute selected.BillingCity = 'San Francisco'.update(myAcct). insert(a). Name. Database.SaveResult SR = database. see Bulk DML Exception Handling on page 278. the sObject record's ID field is used by default. if the field does not have the Unique attribute selected. To insert an sObject record.” For more information. The optional opt_allOrNone parameter specifies whether the operation allows partial success. see “Creating Custom Fields” in the Salesforce online help.000 records and all of them are being updated. For example. the createable property of the sObject must be set to true. respectively. if specified) to determine whether it should create a new object record or update an existing one: • • • If the key is not matched. Rules and Guidelines When upserting sObject records. The upsert statement automatically modifies the values of certain fields such as LastModifiedDate. Each upsert statement consists of two operations.SObjectField External_ID_Field. “ABC123” is matched with “abc123. Find the token for the field by using the fields special method. the sObject record's ID field is used by default. If this is the case. LastModifiedById. consider the following rules and guidelines: • • • • • Certain sObjects cannot be inserted or updated.Reference Upsert Operation If opt_external_id is not specified. Schema.SObjectField f = Account. Each of these operations is subject to the runtime limits for insert and update. If the key is matched multiple times. “ABC123” is matched with “abc123. the updateable property of the sObject must be set to true. a field token. Database Method Syntax • • UpsertResult Database. Schema. If External_ID_Field is not specified.SObjectField. Additionally. You cannot explicitly specify these values in your Apex. Note: Custom field matching is case-insensitive only if the custom field has the Unique and Treat "ABC" and "abc" as duplicate values (case insensitive) attributes selected as part of the field definition. You must supply a non-null value for all required fields on any record that will be inserted. How Upsert Chooses to Insert or Update Upsert uses the sObject record's primary key (or the external ID. The External_ID_Field is of type Schema.” For more information.Upsert(sObject[] recordsToUpsert. If you specify false for this parameter and a record fails. see “Creating Custom Fields” in the Salesforce online help. If the key is matched once. (See Understanding Execution Governors and Limits on page 214) 272 . Boolean opt_allOrNone) UpsertResult[] Database.SObjectField External_ID_Field. then an error is generated and the object record is neither inserted or updated. if you upsert more than 10. and why. This custom field must be created with the External Id attribute selected. but related record IDs can. If this is the case. and SystemModstamp. the remainder of the DML operation can still succeed. then a new object record is created. Boolean opt_allOrNone) The optional External_ID_Field parameter is an optional variable that specifies the custom field that should be used to match records that already exist in your organization's data.Upsert(sObject recordToUpsert. For example. The ID of an sObject record cannot be modified. one for inserting records and one for updating records. the context user must have the “View All” object-level permission for the target object or the “View All Data” permission so that upsert does not accidentally insert a duplicate record. which failed. you receive an error. that is. Note: Custom field matching is case-insensitive only if the custom field has the Unique and Treat "ABC" and "abc" as duplicate values (case insensitive) attributes selected as part of the field definition. This method returns a result object that can be used to verify which records succeeded. To update an sObject record. Schema.MyExternalId. then the existing object record is updated.Fields. This action is interpreted as an update. You can use foreign keys to upsert sObject records if they have been set as reference fields. } catch (DmlException e) { // Process exception here } 273 . If this field contains a value.UpsertResult objects is returned with the upsert database method. A Boolean value that is set to true if the DML operation was successful for this object. Upsert is not supported with some sObjects. that is. you cannot change the account's name without updating the account itself with a separate DML statement. An UpsertResult object has the following methods: Name getErrors Type Database. see Database Error Object Methods on page 389. for (Account a : acctsList) { a. and also inserts a new account located in San Francisco: Account[] acctsList = [SELECT Id. } Account newAcct = new Account(Name = 'Acme'. acctsList.Reference Upsert Operation • • • The upsert statement can only set the ID of related sObject records.BillingCity = 'Mumbai'. For more information. an array of one or more database error objects providing the error code and description. UpsertResult Object An array of Database. BillingCity = 'San Francisco'). If only one sObject is passed in. see Field Types in the Object Reference for Salesforce and Force. getId ID isCreated Boolean isSuccess Boolean DML Statement Examples The following example updates the city name for all existing accounts located in the city formerly known as Bombay. the first element in the UpsertResult array matches the first element passed in the sObject array. However. Each element in the UpsertResult array corresponds to the sObject array passed as the sObject[] parameter in the upsert database method. The ID of the sObject you were trying to update or insert. If this field is empty. if updating an existing contact. See sObjects That Do Not Support DML Operations on page 275. false otherwise. the object was successfully updated or inserted. For example.Error [] Description If an error occurred. Fields on related records cannot be modified with upsert. A Boolean value that is set to true if the record was created. BillingCity FROM Account WHERE BillingCity = 'Bombay']. you can specify the contact's related account record by setting the value of the AccountId field. and so on. the UpsertResults array contains a single element. the operation was not successful for that object. For more information.add(newAcct).com. Name. the second element corresponds with the second element. try { upsert acctsList. false if the record was updated. (SELECT Id. Product2Id = lineItem. public void upsertExample() { Opportunity opp = [SELECT Id. create a custom text field on the Asset object named Line_Item_Id__c and mark it as an external ID. For information on custom fields.Product2Id. /* This class demonstrates and tests the use of the * partial processing DML operations */ public class dmlSamples { /* This method accepts a collection of lead records and creates a task for the owner(s) of any leads that were created as new. This next example uses upsert and an external ID field Line_Item_Id__c on the Asset object to maintain a one-to-one relationship between an asset and an opportunity line item. and Product2Id for each asset Asset asset = new Asset(Name = lineItem.Product2Id). assets. } } Database Method Example The following is an example that uses the Database upsert method to upsert a collection of leads that are passed in. Note: Before running this sample.upsertResult> upsertLeads(List<Lead> leads) { 274 . // Create an asset for each line item on the opportunity for (OpportunityLineItem lineItem:opp. the remaining records are still inserted or updated. } catch (DmlException e) { System.Id. not updated as a result of the upsert operation */ public static List<Database. PricebookEntry.debug(e.PricebookEntry. The task sObjects are saved in a list. It iterates through the results and adds a new task to each record that was processed successfully. } try { upsert assets Line_Item_ID__c. that is. which is then bulk inserted.PricebookEntry.Name FROM OpportunityLineItems) FROM Opportunity WHERE HasOpportunityLineItem = true LIMIT 1]. Line_Item_ID__c = lineItem. that is. AccountId. AccountId = opp.getMessage()). see Bulk DML Exception Handling on page 278. This example also contains a test method for testing the example. Name. This example allows for partial processing of records. Use of upsert with an external ID can reduce the number of DML statements in your code. AccountId. Asset[] assets = new Asset[]{}. PricebookEntry. in case some records fail processing.Reference Upsert Operation Note: For more information on processing DmlExceptions.add(asset).Name.OpportunityLineItems) { //This code populates the line item Id. and help you to avoid hitting governor limits (see Understanding Execution Governors and Limits). see the Salesforce online help. // // // // This line upserts the assets list with the Line_Item_Id__c field specified as the Asset field that should be used for matching the record that should be upserted.AccountId. */ for(Database.upsert(leads.isCreated()) tasks.upsertLeads(leads). In this case the unique identifier for the insert or update decision is the Salesforce record ID. /* Exercise the method */ List<Database.getId()). } /* Switch to the runtime limit context */ Test.upsertResult> uResults = Database. /* ID set for asserting the tasks were created as expected */ Set<Id> ids = new Set<Id>(). asserting success and adding the new ID to the set for use in the comprehensive assertion phase below. } } } sObjects That Do Not Support DML Operations DML operations are not supported with the following sObjects in Apex: • AccountTerritoryAssignmentRule 275 . otherwise an update will be attempted.assert(result. */ for(Lead l:[SELECT Id.isSuccess()).Reference sObjects That Do Not Support DML Operations /* Perform the upsert.upsertResult result:results) { System.upsertResult> results = DmlSamples. /* Iterate over the results.add(new Lead(LastName = 'testLead'. */ List<Database.startTest(). i++) { leads. for(Database. insert them */ Database. /* Switch back to the test context for limits */ Test. /* This is the list for new tasks that will be inserted when new leads are created. ids. Company = 'testCompany')). */ List<Task> tasks = new List<Task>().l. WhoId = result. If the record ID is null the row will be inserted.tasks.upsertResult result:uResults) { if (result.add(new Task(Subject = 'Follow-up'. (SELECT Subject FROM Tasks) FROM Lead WHERE Id IN :ids]) { System.assertEquals(1. /* Create a set of leads for testing */ for(Integer i = 0.insert(tasks). } /* Assert that exactly one task exists for each lead that was inserted.i < 100.false). } public static testMethod void testUpsertLeads() { /* We only need to test the insert side of upsert */ List<Lead> leads = new List<Lead>(). } /* If there are tasks to be inserted.stopTest().add(result. return uResults.isSuccess() && result.getId())).size()). Reference sObjects That Cannot Be Used Together in DML Operations • • • • • • • • • • • • • • • • AccountTerritoryAssignmentRuleItem ApexComponent ApexPage BusinessHours BusinessProcess CategoryNode CurrencyType DatedConversionRate ProcessInstance* Profile RecordType SelfServiceUser StaticResource UserAccountTeamMember UserTerritory WebLink * You cannot create. update or delete ProcessInstance in the SOAP API. You can update a user in a transaction with other sObjects in Apex code that is saved using Salesforce. sObjects That Cannot Be Used Together in DML Operations Some sObjects require that you perform DML operations on only one type per transaction.com API version 14. Other DML operations are not allowed. For example. you cannot insert an account.0 and earlier.com API version 14.0 and earlier.com API version 15. You can insert a user in a transaction with other sObjects in Apex code that is saved using Salesforce.0 and earlier 276 .com API version 14. • GroupMember You can only insert and update a group member in a transaction with other sObjects in Apex code that is saved using Salesforce. The following sObjects cannot be used together in a transaction: • • FieldPermissions Group You can only insert and update a group in a transaction with other sObjects. then insert a user or a group member in a single transaction.0 and later if UserRoleId is specified as null. • • • • • • ObjectPermissions PermissionSet PermissionSetAssignment QueueSObject SetupEntityAccess User You can insert a user in a transaction with other sObjects in Apex code that is saved using Salesforce. Account a. However. userroleid = r.com API version 15.runAs (thisUser) { Profile p = [SELECT Id FROM Profile WHERE Name='Standard User']. The following example shows how to enclose mixed DML operations within System. for example. // Insert account as current user System.getUserId()]. @isTest private class MixedDML { static testMethod void MixedDMLExample() { User u. u = new User(alias = 'jsmtih'. If you are using a Visualforce page with a custom controller. Mixed DML Operations Are Allowed in Test Methods in System. This enables you.com API version 17. localesidkey='en_US'. username='jsmith@acme. then create a user with a submit button.0 and later if the following fields are not also updated: ◊ ◊ ◊ ◊ ◊ ◊ • • • • UserRoleId IsActive ForecastEnabled IsPortalEnabled Username ProfileId UserRole UserTerritory Territory Custom settings in Apex code that is saved using Salesforce. It creates a test user and a test account.RunAs() Blocks Test methods allow for performing mixed DML operations between the sObjects listed earlier and other sObjects if the code that performs the DML operations is enclosed within System. } 277 . a = new Account(name='Acme'). you could create an account with a save button. emailencodingkey='UTF-8'.com'). User thisUser = [SELECT Id FROM User WHERE Id = :UserInfo. Replace the user role value in the query with an existing user role in your organization before running this example. email='jsmith@acme. Create a second method that uses the future annotation to manipulate a second sObject type.0 and earlier. languagelocalekey='en_US'. lastname='Smith'.com'.Reference sObjects That Cannot Be Used Together in DML Operations You can update a user in a transaction with other sObjects in Apex code that is saved using Salesforce.Id. profileid = p. you can perform DML operations on different types of sObjects in subsequent requests. The second block runs in the test user’s context and updates the account. Create a method that performs a DML operation on one type of sObject. there are no restrictions on delete DML operations. insert u. insert a.Id. UserRole r = [SELECT Id FROM UserRole WHERE Name='SalesRep']. You can perform DML operations on more than one type of sObject in a single class using the following process: 1.runAs blocks to avoid the mixed DML error. you can only perform DML operations on a single type of sObject within a single request or action. to create a user with a role and other sObjects in the same test. The first block runs in the current user’s context. 2. timezonesidkey='America/Los_Angeles'. For these sObjects. for example.runAs method blocks. 2.Reference Bulk DML Exception Handling // Update account as the new user System. “Too many batch retries in the presence of Apex triggers and partial failures. Any record that generates an error due to issues such as validation rules or unique index violations is set aside. Math. See Understanding Execution Governors and Limits on page 214. the runtime engine attempts at least a partial save: 1.com'. Standard static methods are similar to Java and are always of the form: Class. the following expression rounds the value of 1. or if the all_or_none parameter of a database DML method was specified as true. as well as more complex objects. and if any record generates an error (perhaps because of race conditions) it is also set aside. 3. } } } Bulk DML Exception Handling Exceptions that arise from a bulk DML call (including any recursive DML operations in triggers that are fired as a direct result of the call) are handled differently depending on where the original call came from: • When errors occur because of a bulk DML call that originates directly from the Apex DML statements.75 to the nearest Integer without using any other values. If any record generates an error. governor limits are reset to their original state before the first attempt.method(args) Standard static methods for primitive data types do not have an implicit parameter. the entire operation fails with the error message. 278 . the runtime engine follows the “all or nothing” rule: during a single operation. If there were additional errors during the second attempt.salesforce. If there were errors during the first attempt.roundToLong(1. and are invoked with no object context. For example. During the first attempt. When errors occur because of a bulk DML call that originates from the SOAP API.75). All records that didn't generate an error during the first attempt are processed.” Note: During the second and third attempts. update a.runAs(u) { a. the runtime engine makes a second attempt which includes only those records that did not generate errors.website = 'www. all records must be updated successfully or the entire operation rolls back to the point immediately preceding the DML statement. the runtime engine makes a third and final attempt which includes only those records that did not generate errors during the first and second attempts. • Apex Standard Classes and Methods Apex provides standard classes that contain both static and instance methods for expressions of primitive data types. the runtime engine processes all records. set. 'My Error Message'). The Apex standard classes are grouped into the following categories: • • • • • • Primitives Collections Enums sObjects System Exceptions Apex Primitive Methods Many primitive data types in Apex have methods that can be used to do additional manipulation of the data. encoding it as a PDF file. world'. Some classes use a namespace as a grouping mechanism for their methods. The primitives that have methods are: • • • • • • • • • • Blob Boolean Date Datetime Decimal Double ID Long String Time Blob Methods The following is the system static method for Blob. For example: String s = 'Hello. such as a list.Message myMsg = new ApexPages. Note: If a method is called with an object expression that evaluates to null.Message(ApexPages. or string.length().Reference Apex Primitive Methods All instance methods occur on expressions of a particular data type. For example. Name toPdf Arguments String S Return Type Blob Description Creates a binary object out of the given string.FATAL. Integer i = s. the Apex runtime engine throws a null pointer exception. ApexPages. 279 . the message class uses the ApexPages namespace. see Primitive Data Types on page 26. such as AccountHistory.valueOf('true'). If the specified argument is null. Blob myBlob = Blob. Integer size = myBlob. when the field type corresponds to a Boolean type. Name size Arguments Return Type Integer Description Returns the number of characters in the blob. Name valueOf Arguments String s Return Type Boolean Description Converts the specified string to a Boolean value and returns true if the specified string value is 'true'. System. returns false. Otherwise. b). The following are the instance methods for Blob. Blob myBlob = Blob.size(). toString String Casts the blob into a String. Boolean Methods The following are the static methods for Boolean. For more information on Blobs. valueOf Object fieldValue Boolean Converts the specified history tracking field value to a Boolean value. this method throws an exception.valueof(myString). Example: Boolean b = Boolean.assertEquals(true. Use this method with the OldValue or NewValue fields of history sObjects.valueof(myString). For example: String myString = 'StringToBlob'. like a checkbox field. 280 .Reference Apex Primitive Methods Name valueOf Arguments String S Return Type Blob Description Casts the specified String S to a Blob. For example: String myString = 'StringToBlob'. 2). month (1=Jan). parse String Date Date Constructs a Date from a String.newinstance(1960.field == 'IsPlatinum__c') { Boolean oldValue = Boolean. 2.debug('Field: ' + ah.valueOf(ah. } For more information on Boolean. The String should use the standard date format 281 .parse('12/27/2009').Field).OldValue).OldValue. if (ah.valueOf(ah. see Primitive Data Types on page 26. The following example creates the date February 17th. Name daysInMonth Arguments Integer year Integer month Return Type Integer Description Returns the number of days in the month for the specified year and month (1=Jan) The following example finds the number of days in the month of February in the year 1960: Integer numberDays = date. The following example works in some locales: date mydate = date. isLeapYear newInstance Integer year Integer year Integer month Integer date Boolean Date Returns true if the specified year is a leap year Constructs a Date from Integer representations of the year.daysInMonth(1960. for(AccountHistory ah : ahlist) { System.NewValue). today valueOf Date String s Date Returns the current date in the current user's time zone Returns a Date that contains the value of the specified String.NewValue FROM AccountHistory]. 1960: Date myDate = date. Date Methods The following are the system static methods for Date. 17). and day. Boolean newValue = Boolean.Reference Apex Primitive Methods Name Arguments Return Type Description Example: List<AccountHistory> ahlist = [SELECT Field. The format of the String depends on the local date format. addMonths addYears Integer addlMonths Date Integer addlYears Date Adds the specified number of addlMonths to a Date Adds the specified number of addlYears to a Date 282 . stringDate = year + '-' + month + day + ' ' + hour + ':' + + ':' + second.valueOf(stringDate). when the field is a Date field.NewValue). minute = '20'. month = '10'. such as AccountHistory.NewValue FROM AccountHistory]. Name addDays Arguments Integer addlDays Return Type Date Description Adds the specified number of addlDays to a Date.addDays(2). if (ah. 2. for(AccountHistory ah : ahlist) { System.valueOf(ah.OldValue.field == 'MyDate__c') { Date oldValue = Date. day = '5'.Reference Apex Primitive Methods Name Arguments Return Type Description “yyyy-MM-dd HH:mm:ss” in the local time zone.newInstance(1960. For example: date myDate = date. Example: List<AccountHistory> ahlist = [SELECT Field.debug('Field: ' + ah. date newDate = mydate. Date newValue = Date.valueOf(ah.OldValue). } The following are the instance methods for Date. hour = '12'. For example: string string string string string string string + '-' minute year = '2008'. 17). Use this method with the OldValue or NewValue fields of history sObjects. Date myDate = date. valueOf Object fieldValue Date Converts the specified history tracking field value to a Date.Field). second = '20'. For example: date myDate = date.newInstance(2008. Returns the day-of-year component of a Date. 1999. 1999 would be day 5. isSameDay month monthsBetween Integer Date compDate Integer Returns the month component of a Date (1=Jan) Returns the number of months between the Date that called the method and the compDate. For example. 1. For example. 1999 would be day 36. February 5. For example: date startDate = date.today(). 1. 30). depending on the context user's locale. integer numberDaysDue = startDate. 1).newInstance(2008.isSameDay(dueDate). date dueDate = date. and Monday in European locales. February 5. toStartOfMonth Date toStartOfWeek Date year Integer Returns the year component of a Date 283 .Reference Apex Primitive Methods Name day Arguments Return Type Integer Integer Description Returns the day-of-month component of a Date. date weekStart = myDate.daysBetween(dueDate). For example: date myDate = date. Returns the number of days between the Date that called the method and the compDate. For example. Returns the start of the week for the Date that called the method. the start of a week is Sunday in the United States locale. Returns the first of the month for the Date that called the method. For example. July 14.toStartofWeek().today(). 1999 returns July 1. March 1 and March 30 of the same year have 0 months between them. boolean dueNow = myDate.newInstance(2008. 1. dayOfYear daysBetween Date compDate Integer format String Date compDate Boolean Returns the Date as a string using the locale of the context user Returns true if the Date that called the method is the same as the compDate. ignoring the difference in dates. date dueDate = date. If the Date that calls the method occurs after the compDate. 30). For example. the return value is negative. 1. month (1=Jan). The returned date is in the GMT time zone. and second in the GMT time zone newInstanceGmt Integer year Integer month Integer date Datetime newInstanceGmt Integer year Integer month Integer date Integer hour Datetime 284 . hour. 30. minute. day.newInstance(2008. 2). 12. The returned date is in the GMT time zone. month (1=Jan). Constructs a Datetime from Integer representations of the year. 1). minute. 1970. Constructs a Datetime from Integer representations of the year. and day at midnight in the GMT time zone Constructs a Datetime from Integer representations of the year. hour. see Primitive Data Types on page 26. newInstance Date Date Time Time Datetime newInstance Integer year Integer month Integer day Datetime newInstance Integer year Integer month Integer day Integer hour Integer minute Integer second Datetime Constructs a Datetime from Integer representations of the year. The returned date is in the GMT time zone. newInstanceGmt Date date Time time Datetime Constructs a DateTime from the specified date and time in the GMT time zone. For example: Datetime myDate = datetime. month (1=Jan). and day at midnight in the local time zone. Constructs a DateTime from the specified date and time in the local time zone. 12. For example: datetime myDate = datetime.Reference Apex Primitive Methods For more information on Dates. 12. day. Datetime Methods The following are the system static methods for Datetime. Name newInstance Arguments Long l Return Type Datetime Description Constructs a DateTime and initializes it to represent the specified number of milliseconds since January 1.newInstance(2008. month (1=Jan). The returned date is in the GMT time zone. and second in the local time zone. 00:00:00 GMT. 285 . '10/14/2011 11:46 AM'). valueOf Object fieldValue Datetime Converts the specified history tracking field value to a Datetime. system. day = '5'. Datetime dt = DateTime. valueOf String s Datetime Returns a Datetime that contains the value of the specified String. Datetime myDate = datetime. The returned date is in the GMT time zone. minute = '20'.assertEquals( myDtString. second = '20'. month = '10'. The returned date is in the GMT time zone. This example uses parse to create a Datetime from a date passed in as a string and that is formatted for the English (United States) locale. String myDtString = dt. hour = '12'. For example: string string string string string string string + '-' minute year = '2008'.parse( '10/14/2011 11:46 AM').valueOf(stringDate).Reference Apex Primitive Methods Name Arguments Integer minute Integer second Return Type Description now Datetime Returns the current Datetime based on a GMT calendar. For example: datetime myDateTime = datetime. The format of the returned datetime is: 'MM/DD/YYYY HH:MM PERIOD' parse String datetime Datetime Constructs a Datetime from the String datetime in the local time zone and in the format of the user locale.format().now(). stringDate = year + '-' + month + day + ' ' + hour + ':' + + ':' + second. The String should use the standard date format “yyyy-MM-dd HH:mm:ss” in the local time zone. You may need to change the format of the date string if you have a different locale. Reference Apex Primitive Methods Name Arguments Return Type Description Use this method with the OldValue or NewValue fields of history sObjects. 17).valueOf(ah.addDays(2). when the field is a Date/Time field. such as AccountHistory.OldValue. Example: List<AccountHistory> ahlist = [SELECT Field. For example: datetime myDate = datetime. The String should use the standard date format “yyyy-MM-dd HH:mm:ss” in the GMT time zone The following are the instance methods for Datetime.NewValue FROM AccountHistory]. addHours addMinutes addMonths addSeconds addYears date Integer addlHours Datetime Adds the specified number of addlHours to a Datetime Adds the specified number of addlMinutes to a Datetime Adds the specified number of addlMonths to a Datetime Adds the specified number of addlSeconds to a Datetime Adds the specified number of addlYears to a Datetime Returns the Date component of a Datetime in the local time zone of the context user.valueOf(ah. datetime newDate = mydate. Datetime newValue = Datetime. Name addDays Arguments Integer addlDays Return Type Datetime Description Adds the specified number of addlDays to a Datetime. for(AccountHistory ah : ahlist) { System.field == 'MyDatetime__c') { Datetime oldValue = Datetime.NewValue).OldValue).Field).newInstance (1960. if (ah.debug('Field: ' + ah. } valueOfGmt String s Datetime Returns a Datetime that contains the value of the specified String. Return the Date component of a Datetime in the GMT time zone Integer addlMinutes Datetime Integer addlMonths Datetime Integer addlSeconds Datetime Integer addlYears Datetime Date Date dateGMT 286 . 2. format String format String dateFormat String For more information on the Java simple date format. 287 . 2. 1999 08:30:12 would be day 36. For example. 36). dayGmt Integer dayOfYear Integer dayOfYearGmt Integer Returns the day-of-year component of a Datetime in the GMT time zone. For example: Datetime myDT = Datetime.Reference Apex Primitive Methods Name day Arguments Return Type Integer Description Returns the day-of-month component of a Datetime in the local time zone of the context user. 1999 08:30:12 would be day 5. see Java SimpleDateFormat. Valid time zone values for the timezone argument are the time zones of the Java TimeZone class that correspond to the time zones returned by the TimeZone. String myDate = myDT. Converts the date to the local time zone and returns the converted date as a formatted string using the locale of the context user. If the supplied time zone is not in the correct format. system. GMT is used. If the time zone cannot be determined. 12).format('h:mm a'). February 5. If the time zone cannot be determined. For example. see Java SimpleDateFormat. Returns the day-of-month component of a Datetime in the GMT time zone. 2008 08:30:12 would be day 36. For more information on the Java simple date format. Datetime myDate = datetime. For example. February 5. We recommend you use full time zone names.getAvailableIDs method in Java. February 5. GMT is used. February 5. GMT is used. Returns the day-of-year component of a Datetime in the local time zone of the context user. format String dateFormat String timezone String Converts the date to the specified time zone and returns the converted date as a string using the supplied Java simple date format.newInstance (2008. Converts the date to the local time zone and returns the converted date as a string using the supplied Java simple date format.now(). 5.dayOfYear(). For example. 30. 8.assertEquals (myDate. not the three-letter abbreviations. 1999 08:30:12 would be day 5. Reference Apex Primitive Methods Name Arguments Return Type Description This example uses format to convert a GMT date to the America/New_York time zone and formats the date using the specified date format. System. String strConvertedDate = GMTDate. strConvertedDate).format('MM/dd/yyyy HH:mm:ss'.formatLong()=' + dt.formatLong()). 1.10. // Date is converted to // the new time zone and is adjusted // for daylight saving time.12.assertEquals( '06/01/2011 08:01:05'. getTime Long Integer Integer Datetime compDt Boolean Returns the number of milliseconds since January 1. Datetime GMTDate = Datetime.5). 30). For example: datetime myDate = datetime. // Writes 12/28/2012 10:00:00 AM PST System. 'America/New_York').12. hour hourGmt isSameDay 288 .1. datetime dueDate = datetime.debug('dt. 1970. For more information on the Java simple date format.1. 00:00:00 GMT represented by this DateTime object Returns the hour component of a Datetime in the local time zone of the context user Returns the hour component of a Datetime in the GMT time zone Returns true if the Datetime that called the method is the same as the compDt in the local time zone of the context user. boolean dueNow = myDate. formatLong String Converts the date to the local time zone and returns the converted date in long date format. formatGmt StringdateFormat String Returns a Datetime as a string using the supplied Java simple date format and the GMT time zone.newInstance( 2012.28.0).6.0.isSameDay(dueDate).newInstanceGmt(2011. For example: // Passing local date based on the PST // time zone Datetime dt = DateTime.now().newInstance(2008. see Java SimpleDateFormat. Name valueOf Arguments Double d Long l Return Type Decimal Decimal Description Returns a Decimal that contains the value of the specified Double. Decimal Methods The following are the system static methods for Decimal. valueOf 289 .Reference Apex Primitive Methods Name millisecond Arguments Return Type Integer Integer Integer Integer Integer Integer Integer Integer Time Time Integer Integer Description Return the millisecond component of a Datetime in the local time zone of the context user. Return the millisecond component of a Datetime in the GMT time zone. see Primitive Data Types on page 26. Returns the minute component of a Datetime in the local time zone of the context user Returns the minute component of a Datetime in the GMT time zone Returns the month component of a Datetime in the local time zone of the context user (1=Jan) Returns the month component of a Datetime in the GMT time zone (1=Jan) Returns the second component of a Datetime in the local time zone of the context user Returns the second component of a Datetime in the GMT time zone Returns the time component of a Datetime in the local time zone of the context user Returns the time component of a Datetime in the GMT time zone Returns the year component of a Datetime in the local time zone of the context user Returns the year component of a Datetime in the GMT time zone millisecondGmt minute minuteGmt month monthGmt second secondGmt time timeGmt year yearGmt For more information about the Datetime. Returns a Decimal that contains the value of the specified Long. the number of decimal places. system.4567'. Scientific notation will be used if an exponent is needed. Integer scale Decimal divide Decimal divisor. The following are the instance methods for Decimal. Divides this Decimal by divisor.78). 2. that is. of the result using scale.4567.UP). Object roundingMode Decimal Divides this Decimal by divisor. sets the scale. D. rounds the value using roundingMode. For example: String temp = '12. that is. and sets the scale. Decimal divDec = myDecimal.Reference Apex Primitive Methods Name valueOf Arguments String s Return Type Decimal Description Returns a Decimal that contains the value of the specified String. intValue longValue Integer Long Returns the Integer value of this Decimal. 290 . Returns the String value of this Decimal using the locale of the context user. doubleValue format Double String Returns the Double value of this Decimal.190: Decimal D = 19. 1. Integer scale.assertEquals(divDec. For example: Decimal myDecimal = 12.divide (7. System. Decimal divisor. As in Java. Decimal myDecimal = decimal. For more information about the valid values for roundingMode. see Rounding Mode.valueOf(temp). of the result using scale. the string is interpreted as representing a signed Decimal. Returns the Long value of this Decimal.RoundingMode. the number of decimal places. 3). In the following example.Divide(100. Name abs divide Arguments Return Type Decimal Description Returns the absolute value of the Decimal. D has the value of 0. and if necessary. Integer precision2 = D2.assertEquals(L1. this mode rounds towards the even neighbor. Long L2= D2. 6). The Math method pow does accept negative values. Integer precision1 = D1.12. system. If you use MyDecimal. see Rounding Mode.767.9744). For example: Decimal D1 = 5. system. Decimal powDec = myDecimal. in which case.123. if the Decimal value was 123. precision returns 6.assertEquals(powDec.assertEquals(precision1. round Long Returns the rounded approximation of this Decimal.pow(2). For example. 16.45.round().assertEquals(precision2.pow(0).precision().round(). system.45. The value of exponent must be between 0 and 32.5. precision returns 5. system. precision Integer Returns the total number of digits for the Decimal. 291 . Note that this rounding mode statistically minimizes cumulative error when applied repeatedly over a sequence of calculations. For example: Decimal D1 = 123.123.2.precision(). For more information about half-even rounding mode. The number is rounded to zero decimal places using half-even rounding mode.Reference Apex Primitive Methods Name pow Arguments Integer exponent Return Type Decimal Description Returns the value of this decimal raised to the power of exponent. 5). Long L1 = D1. 1 is returned. If the Decimal value is 123. it rounds towards the “nearest neighbor” unless both neighbors are equidistant. that is. Decimal D2 = 123. For example: Decimal myDecimal = 4. Decimal D2= 5. 6). 767. the scale is determined by the item from which the Decimal is created: • If the Decimal is created as part of a query. the number of decimal places. If the Decimal is created from a String. round System.RoundingMode roundingMode Sets the scale of the Decimal to the given number of decimal places. if necessary. system. if necessary. the scale is the number of characters after the decimal point of the String.Reference Apex Primitive Methods Name Arguments Return Type Description system. If you do not explicitly set the scale for a Decimal.assertEquals(L2. using the rounding mode specified by roundingMode .assertEquals(L3. Sets the scale of the Decimal to the given number of decimal places. the scale is based on the scale of the field returned from the query. For more information about the valid values for roundingMode. Decimal D3= -5. scale Integer Integer scale Decimal setScale • • setScale Integer scale. in which case. For more information about half-even rounding mode. -6).round(). see Rounding Mode. Decimal System. the scale is determined by converting the number to a String and then using the number of characters after the decimal point. see Rounding Mode. Long L3= D3. If the Decimal is created from a non-decimal number. 292 .768 and 32. that is. Half-even rounding mode rounds towards the “nearest neighbor” unless both neighbors are equidistant. 5). The value of scale must be between -32. The number is rounded to zero decimal places using the rounding mode specified by roundingMode. Returns the scale of the Decimal. The value of scale must be between –33 and 33. For more information about the valid values for roundingMode. see Rounding Mode. using half-even rounding. this mode rounds towards the even neighbor.RoundingMode Long roundingMode Returns the rounded approximation of this Decimal.7. 1: DOWN round mode result: -1 • Input number -2. If the Decimal is created from a non-decimal number. Note that this rounding mode never decreases the calculated value.7: CEILING round mode result: -2 Rounds towards zero. Name CEILING Description Rounds towards positive infinity. if the result is positive. Rounding Mode Rounding mode specifies the rounding behavior for numerical operations capable of discarding precision. it behaves the same as the DOWN rounding mode. For example: • Input number 5. Note that this rounding mode never increases the magnitude of the calculated value. Returns the String value of this Decimal. this mode behaves the same as the UP rounding mode.Reference Apex Primitive Methods Name Arguments Return Type Description If you do not explicitly set the scale for a Decimal. This rounding mode always discards any fractions (decimal points) prior to executing.1: DOWN round mode result: 1 • Input number -1. That is. If the Decimal is created from a String. see Primitive Data Types on page 26.5: CEILING round mode result: 6 • Input number 1.1: CEILING round mode result: 2 • Input number -1. the scale is determined by the item from which the Decimal is created: • If the Decimal is created as part of a query. Each rounding mode indicates how the least significant returned digit of a rounded result is to be calculated. the scale is determined by converting the number to a String and then using the number of characters after the decimal point. the scale is based on the scale of the field returned from the query. • • stripTrailingZeros toPlainString Decimal String Returns the Decimal with any trailing zeros removed.5: DOWN round mode result: 5 • Input number 1.7: DOWN round mode result: -2 DOWN 293 . without using scientific notation. if the result is negative. The following are the valid values for roundingMode. the scale is the number of characters after the decimal point of the String. For more information on Decimal.1: CEILING round mode result: -1 • Input number -2. For example: • Input number 5. 7: FLOOR round mode result: -3 Rounds towards the “nearest neighbor” unless both neighbors are equidistant.7: HALF_UP round mode result: -3 Asserts that the requested operation has an exact result.1: FLOOR round mode result: -2 • Input number -2. if the result is positive. If this rounding mode is specified on an operation that yields an inexact result.1: HALF_DOWN round mode result: 1 • Input number -1. this mode rounds up.7: HALF_DOWN round mode result: -2 Rounds towards the “nearest neighbor” unless both neighbors are equidistant.5.1: HALF_UP round mode result: -1 • Input number -2. it behaves the same as DOWN rounding mode.1: HALF_EVEN round mode result: 1 • Input number -1.5: HALF_EVEN round mode result: 6 • Input number 1. For example: • Input number 5. which means that no rounding is necessary. For example: • Input number 5. For example: • Input number 5. This rounding mode behaves the same as the HALF_UP rounding mode if the digit to the left of the discarded fraction (decimal point) is odd. Note that this rounding mode never increases the calculated value.0: UNNECESSARY round mode result: 1 UNNECESSARY 294 . otherwise. otherwise.1: HALF_DOWN round mode result: -1 • Input number -2. this mode behaves the same as the UP rounding mode. in which case. this rounding method behaves the same as the DOWN rounding method.7: HALF_EVEN round mode result: -3 Note that this rounding mode statistically minimizes cumulative error when applied repeatedly over a sequence of calculations.5: HALF_UP round mode result: 6 • Input number 1.1: FLOOR round mode result: 1 • Input number -1.5: UNNECESSARY round mode result: Exception • Input number 1. this mode rounds towards the even neighbor.Reference Apex Primitive Methods Name FLOOR Description Rounds towards negative infinity.5: FLOOR round mode result: 5 • Input number 1. HALF_DOWN HALF_EVEN HALF_UP Rounds towards the “nearest neighbor” unless both neighbors are equidistant. It behaves the same as the HALF_DOWN rounding method if it is even. this mode behaves the same as theDOWN rounding mode. an Exception is thrown.1: HALF_UP round mode result: 1 • Input number -1. in which case this mode rounds down. That is. in which case. This rounding mode behaves the same as the UP rounding mode if the discarded fraction (decimal point) is > 0.5: HALF_DOWN round mode result: 5 • Input number 1. if negative. For example: • Input number 5.5.1: HALF_EVEN round mode result: -1 • Input number -2. This rounding method behaves the same as the UP rounding method if the discarded fraction (decimal point) is >= 0. For example: • Input number 5. valueOf(ah.NewValue FROM AccountHistory]. For example: • Input number 5.14159').valueOf('3.valueOf(ah. This rounding mode always truncates any fractions (decimal points) prior to executing. such as AccountHistory.OldValue). As in Java. } The following are the instance methods for Double.debug('Field: ' + ah.Field).OldValue. valueOf Object fieldValue Double Converts the specified history tracking field value to a Double value. Example: List<AccountHistory> ahlist = [SELECT Field.Reference Apex Primitive Methods Name UP Description Rounds away from zero.5: UP round mode result: 6 • Input number 1. for(AccountHistory ah : ahlist) { System. Note that this rounding mode never decreases the magnitude of the calculated value.7: UP round mode result: -3 Double Methods The following are the system static methods for Double. like a number field.1: UP round mode result: -2 • Input number -2. For example: Double DD1 = double.1: UP round mode result: 2 • Input number -1. Double newValue = Double. when the field type corresponds to a Double type. Use this method with the OldValue or NewValue fields of history sObjects. the String is interpreted as representing a signed decimal.field == 'NumberOfEmployees') { Double oldValue = Double.NewValue). Name format Arguments Return Type String Description Returns the String value for this Double using the locale of the context user 295 . Name valueOf Arguments String s Return Type Double Description Returns a Double that contains the value of the specified String. if (ah. this mode rounds towards the even neighbor. Long L2= D2. it rounds towards the “nearest neighbor” unless both neighbors are equidistant.Reference Apex Primitive Methods Name intValue Arguments Return Type Integer Description Returns the Integer value of this Double by casting it to an Integer. ID Methods The following are the static methods for ID. Method valueOf Arguments String s Return Type ID Description Converts the specified String into an ID and returns the ID.assertEquals(L3.14159').round(). that is. Double D2= 5.assertEquals(L1. Long L3= D3. 296 . 5). The number is rounded to zero decimal places using half-even rounding mode.assertEquals(value. 3). 6). system. -6). For more information about half-even rounding mode.assertEquals(L2.valueOf('3. For example: Double DD1 = double.7.round(). system. For more information on Double. For example: Double D1 = 5. Note that this rounding mode statistically minimizes cumulative error when applied repeatedly over a sequence of calculations. Integer value = DD1. in which case.5. longValue round Long Long Returns the Long value of this Double Returns the rounded value of this Double. Double D3= -5. Long L1 = D1. system.round(). The following are the instance methods for ID. see Primitive Data Types on page 26. system.intValue(). see Rounding Mode.2. new[0]. Example: Trigger. For more information about describes.SObjectType Returns the token for the sObject corresponding to this ID.0 and later.Id. getSObjectType Schema. If the error message contains HTML markup.0 and later. The exception argument is an Exception object or a custom exception object that contains the error message to mark the record with.addError('bad').Reference Apex Primitive Methods Method addError Arguments String errorMsg Return Type Description Marks a record with a custom error message and prevents any DML operation from occurring.com API version 27. the specified error message is escaped in the Salesforce user interface. If the error message contains HTML markup. This method is primarily used with describe information. see Understanding Apex Describe Information. see Sample: Getting an sObject Token From an ID. Note: For Apex saved using Salesforce. The errorMsg argument is the error message to mark the record with. This method is similar to the addError sObject method.com API version 27. For an example. Note: For Apex saved using Salesforce. the escaped markup displays as text and isn’t rendered in the user interface. the specified error message is escaped in the Salesforce user interface. addError Exception exception Marks a record with a custom error message and prevents any DML operation from occurring. 297 . the escaped markup displays as text and isn’t rendered in the user interface. This method is similar to the addError sObject method. size().size() > 0). then does a describe to obtain the object name and constructs a query dynamicallly. System. sObject[] objDBList = Database. 298 . for(ID objId : objIds) { queryString += 'Id=\'' + objId + '\' OR '.getName() + ' ID ' + sr.SaveResult[] srList = Database.size() > 0).debug('Updated owner ID successfully for ' + dr. public class MyDynamicSolution { @future public static void updateOwner(List<ID> objIds.query(queryString). } else { System.length() . false). // Using the token.put('ownerId'.4).').isSuccess()) { System.debug(e.Reference Apex Primitive Methods Sample: Getting an sObject Token From an ID This sample shows how to use the getSObjectType method to obtain an sObject token from an ID. } } } } } Integer Methods The following are the system static methods for Integer. do a describe // and construct a query dynamically.getName() + ' WHERE '.Error e : sr.DescribeSObjectResult dr = token. ID newOwnerId) { // Validate input System. This list contains IDs of sObjects of the same type.i++) { objDBList[i]. System. String queryString = 'SELECT ownerId FROM ' + dr.update(objDBList. This method gets the sObject token from the first ID in the list.getSObjectType(). // Get the sObject token from the first ID // (the List contains IDs of sObjects of the same type).subString(0.assert(newOwnerId != null). it doesn’t accept sObject types as parameters.debug('Updating ' + dr.getName() + ' returned the following errors. } // Remove the last ' OR' queryString = queryString.i<objDBList. Schema. queryString.SObjectType token = objIds[0]. Note that since it is a future method. newOwnerId).assert(objDBList. The updateOwner method in this sample accepts a list of IDs of the sObjects to update the ownerId field of.getMessage()). for(Database.assert(objIds != null). } Database. Schema.getDescribe().getErrors()) { System. System.assert(objIds.getId()). It then queries for all sObjects and updates their owner ID fields to the new owner ID. The second parameter is the new owner ID.SaveResult sr : srList) { if (sr. // Update the owner ID on the sObjects for(Integer i=0. for(Database. this is why it accepts IDs of sObjects. NewValue).debug('Field: ' + ah. } The following are the instance methods for Integer.valueOf(ah. For example: Integer myInt = integer. Example: List<AccountHistory> ahlist = [SELECT Field. for(AccountHistory ah : ahlist) { System. when the field type corresponds to an Integer type.OldValue). see Primitive Data Types on page 26.valueOf('123'). such as AccountHistory. like a number field. As in Java. Long Methods The following is the system static method for Long.Field). Name format Arguments Return Type String Description Returns the integer as a string using the locale of the context user For more information on integers. if (ah.Reference Apex Primitive Methods Name valueOf Arguments String s Return Type Description Integer Returns an Integer that contains the value of the specified String. 299 . As in Java. the string is interpreted as representing a signed decimal Long.valueOf(ah.field == 'NumberOfEmployees') { Integer oldValue = Integer.OldValue. Use this method with the OldValue or NewValue fields of history sObjects. valueOf Object fieldValue Integer Converts the specified history tracking field value to an Integer value.NewValue FROM AccountHistory]. Name valueOf Arguments String s Return Type Long Description Returns a Long that contains the value of the specified String. Integer newValue = Integer. For example: Long L1 = long. the String is interpreted as representing a signed decimal integer.valueOf('123456789'). or null. escapeSingleQuotes String s format String s List<String> arguments String fromCharArray List<Integer> charArray String String Returns a String from the values of the list of integers. empty (''). String Methods The following are the system static methods for String. see Primitive Data Types on page 26.assertEquals( 'SFDC'. See also Splitting String Example. Example: List<String> ls = new List<String> {'SFDCApex'. returns false. to help prevent SOQL injection. Returns the initial sequence of characters as a String that is common to all the specified Strings. Returns true if the specified String is empty ('') or null. prefix).Reference Apex Primitive Methods The following are the instant methods for Long. This method is useful when creating a dynamic SOQL statement. Name format Arguments Return Type String Integer Description Returns the String format for this Long using the locale of the context user Returns the Integer value for this Long intValue For more information on Long. 'SFDCVisualforce'}. For more information on dynamic SOQL. Name Arguments Return Type String Description Returns a String with the escape character (\) added before any single quotation marks in the String s. String prefix = String. isEmpty 300 . Treat the current string as a pattern that should be used for substitution in the same manner as apex:outputText. otherwise. getCommonPrefix List<String> strings isBlank String s String s Boolean Boolean Returns true if the specified String is white space. System. otherwise. returns false. see Dynamic SOQL.getCommonPrefix( ls). valueOf(myDouble).Today(). Returns a String that represents the specified Decimal. String myString = String. Returns a string representation of the specified object argument.34. ls. otherwise. String sDate = String.34'. otherwise. into a single String separated by the specified separator. such as a List. returns false.assertEquals( '10/20/30'. Example: List<Integer> li = new List<Integer> {10. System. myString). returns false. For example: Date myDate = Date. 30}.join( li. isNotEmpty join String separator valueOf Date d String Returns a String that represents the specified Date in the standard “yyyy-MM-dd” format. 301 .Reference Apex Primitive Methods Name isNotBlank Arguments String s String s Object iterableObj Return Type Boolean Boolean String Description Returns true if the specified String is not whitespace. Example: Double myDouble = 12.valueOf(myDate). '/'). and not null. Returns a String that represents the specified Long. Returns true if the specified String is not empty ('') and not null. 20. System.assertEquals( '12.add(10). valueOf Datetime dt String Returns a String that represents the specified Datetime in the standard “yyyy-MM-dd HH:mm:ss” format for the local time zone. String s = String. Returns a String that represents the specified Double. not empty (''). valueOf valueOf Decimal d Double d String String valueOf valueOf valueOf Integer I Long l Object x String String String Returns a String that represents the specified Integer. Example: List<Integer> ls = new List<Integer>(). s). Joins the elements of the specified iterable object. Example: String s = 'Hello Maximillian'. if no toString method is available. String strList = String. this method throws a run-time exception. abbreviate Integer maxWidth Integer offset String Returns an abbreviated version of the String..assertEquals( 'Hello. strList). System.add(20).abbreviate(8). of the specified length and with ellipses appended if the current String is longer than the specified length. System. If the argument is not a String.assertEquals( 8. if available. If maxWidth is less than four. String s2 = s.valueOf(ls). otherwise. The following are the instance methods for String. 20)'.. Otherwise. s2. valueOfGmt Datetime dt String Returns a String that represents the specified Datetime in the standard “yyyy-MM-dd HH:mm:ss” format for the GMT time zone. or any overridden toString method if the argument is a user-defined type. but it appears somewhere in the result. s2). System. Note that the offset is not necessarily the leftmost character in the returned String or the first character following the ellipses.'. abbreviate won’t return a String of length greater than maxWidth.Reference Apex Primitive Methods Name Arguments Return Type Description ls. The returned String has ellipses appended at the start and the end if characters have been removed at these locations. Name abbreviate Arguments Integer maxWidth Return Type String Description Returns an abbreviated version of the String. starting at the specified character offset and of the specified length. the valueOf method converts it into a String by calling the toString method on the argument. Regardless. it returns a String representation of the argument.assertEquals( '(10. returns the original String without ellipses.length()). 302 . so that it appears in the center. center Integer size String Returns a version of the current String of the specified size padded with spaces on the left and right.length()). // Start at M String s2 = s. center Integer size String padStr String Returns a version of the current String of the specified size padded with the specified String on the left and right. System. System..center(9). Example: String s = 'Hello Maximillian'. This method is based on its counterpart abbreviate method in the Apache Commons Lang StringUtils library. the entire String is returned without padding.toTitleCase(char) Java method.. capitalize String Returns the current String with the first letter changed to title case as per the Character.'.assertEquals( ' hello '. System. Example: String s = 'hello maximillian'.Reference Apex Primitive Methods Name Arguments Return Type Description If maxWidth is too small.6). If the specified size is smaller than the current String size.. s2).abbreviate(9. String s2 = s. s2). If the specified size is smaller than the current String size. String s2 = s..assertEquals( 'Hello maximillian'. 303 .assertEquals( '.assertEquals( 9. System.capitalize().Max. this method throws a run-time exception. Example: String s = 'hello'. the entire String is returned without added spaces. s2. s2). so that it appears in the center. compareTo String compString Integer Compares two strings lexicographically.assertEquals(result. System.containsAny('hx'). String myString2 = 'abcd'.assertEquals(result.center(9). Boolean b1 = s. returns false. System. s2). The result is: • A negative Integer if the String that called the method lexicographically precedes compString • A positive Integer if the String that called the method lexicographically follows compString • Zero if the Strings are equal If there is no index position at which the Strings differ. 304 . Boolean b2 = s. true). otherwise. System. then the shorter String lexicographically precedes the longer String.compareTo(myString2). Boolean result = myString1. String s2 = s. For example: String myString1 = 'abcde'. Example: String s = 'hello'. Integer result = myString1. String myString2 = 'abcd'. Note that this method returns 0 whenever the equals method returns true. based on the Unicode value of each character in the Strings.containsAny('x').contains(myString2).Reference Apex Primitive Methods Name Arguments Return Type Description Example: String s = 'hello'. 1).assertEquals( '--hello--'. For example: String myString1 = 'abcde'. contains String compString Boolean Returns true if and only if the String that called the method contains the specified sequence of characters in the compString. containsAny String compString Boolean Returns true if the current String contains any of the characters in the specified String. containsOnly('abcd'). If compString is an empty string or the current String is empty.assertEquals( true.containsIgnoreCase('HE'). Example: String s1 = 'abba'. Boolean b2 = s2. Returns the number of times the specified substring occurs in the current String. otherwise. containsNone String compString Boolean Returns true if the current String doesn’t contain the specified sequence of characters. this method returns a run-time exception. containsWhitespace Boolean String compString Integer Returns true if the current String contains any white space characters.assertEquals( false.Reference Apex Primitive Methods Name Arguments Return Type Description System. otherwise. b1). Boolean b = s. If compString is null. containsIgnoreCase String compString Boolean Returns true if the current String contains the specified sequence of characters without regard to case. otherwise. returns false. b2). returns false. returns false.assertEquals( true.assertEquals( true. returns false. Example: String s = 'hello'. String s2 = 'abba xyz'. b2). b). containsOnly String compString Boolean Returns true if the current String contains characters only from the specified sequence of characters and not any other characters. otherwise. System. this method returns true. countMatches 305 . System. b1).assertEquals( false.containsOnly('abcd'). System. Boolean b1 = s1. System. d2). endsWithIgnoreCase String suffix equals String compString Boolean Note that the == operator also performs String comparison. This method is true whenever the compareTo method returns 0. difference String compString String endsWith String suffix Boolean Boolean Returns true if the String that called the method ends with the specified suffix.) 306 . (== is case-sensitive for ID comparison for the same reason. String myString2 = 'abcd'.equals(myString2). this method returns an empty string.difference('Hello Max'). System. Returns true if the current String ends with the specified suffix. otherwise.difference('Goodbye'). but is case-insensitive to match Apex semantics.assertEquals(result. this method throws a run-time exception. If compString is null.Reference Apex Primitive Methods Name deleteWhitespace Arguments Return Type String Description Returns a version of the current String with all white space characters removed. String d2 = s. If compString is an empty string. returns false. false). Boolean result = myString1. Returns true if the compString is not null and represents the same binary sequence of characters as the String that called the method.assertEquals( 'Max'. System. Returns the difference between the current String and the specified String. Example: String s = 'Hello Jane'. For example: String myString1 = 'abcde'.assertEquals( 'Goodbye'. System. String d1 = s. d1). The only difference between Apex strings and EcmaScript strings is that in EcmaScript. it is returned unchanged. newline or double quote.escapeCsv(). String s2 = s1.9/4.assertEquals( 307 .0'. true). System. System. // Output is: // \"grade\": 3. s2). String s2 = s1. Boolean result = myString1. if required. equalsIgnoreCase String compString Boolean escapeCsv String Returns a String for a CSV column enclosed in double quotes.Reference Apex Primitive Methods Name Arguments Return Type Description Returns true if the compString is not null and represents the same sequence of characters as the String that called the method. escapeEcmaScript String Escapes the characters in the String using EcmaScript String rules. Example: String s1 = 'Max1.assertEquals(result.debug(s2). For example: String myString1 = 'abcd'. the returned String is enclosed in double quotes. newline or double quote.9\/4. ""Max2"""'. System.assertEquals( '"Max1. Also. any double quote characters in the String are escaped with another double quote. a single quote and forward-slash (/) are escaped. This method is based on its counterpart escapeCsv method in the Apache Commons Lang StringEscapeUtils library. If the String doesn’t contain a comma.equalsIgnoreCase(myString2). Example: String s1 = '"grade": 3. If the String contains a comma.0 System. ignoring case. String myString2 = 'ABCD'.escapeEcmaScript(). "Max2"'. This method is based on its counterpart escapeEcmaScript method in the Apache Commons Lang StringEscapeUtils library. System. Unicode characters greater than 0x7f are not escaped. Example: String s1 = '"<Black&White>"'.<.0 entities.<. amp.0'.". quot. // Output: // ". This method is based on its counterpart escapeHtml4 method in the Apache Commons Lang StringEscapeUtils library. lt.escapeHtml3(). System. // Output: // ".debug(s2).9\\/4. // White>. escapeHtml4 String Escapes the characters in a String using HTML 4. s2). String s2 = s1.Black&. escapeXml String Escapes the characters in a String using XML entities. This method is based on its counterpart escapeXml method in the Apache Commons Lang StringEscapeUtils library.escapeHtml4(). 308 . String s2 = s1.0 entities. Example: String s1 = '"<Black&White>"'.Black&. String s2 = s1.escapeXml(). apos). Example: String s1 = '"<Black&White>"'. // White>.". Does not support DTDs or external entities. This method is based on its counterpart escapeHtml3 method in the Apache Commons Lang StringEscapeUtils library.Reference Apex Primitive Methods Name Arguments Return Type Description '\\"grade\\": 3. escapeHtml3 String Escapes the characters in a String using HTML 3. Supports only the five basic XML entities (gt.debug(s2). Example: String s = 'Hello Joe'. this method returns -1.debug(s2). // Output: // ".getLevenshteinDistance( 'Hello Max'). the Levenshtein distance is 3.assertEquals( 3. Each change is a single character modification (deletion. Example: In this example. Each change is a single character modification (deletion. // White>. but the threshold argument is 2. returns -1. Integer i = s. otherwise. Returns the zero-based index of the first occurrence of the specified substring from the point of index i. Integer i = s. which is less than the distance. System. If the indexOf String substring Integer i Integer 309 .getLevenshteinDistance( 'Hello Max'. insertion or substitution). getLevenshtein Distance String s Integer threshold Integer Returns the Levenshtein distance between the current String and the specified String if it is less than or equal than the given threshold. String s = 'Hello Jane'. i). The Levenshtein distance is the number of changes needed to change one String into another. System. 2). If the substring does not occur. getLevenshtein Distance String s Integer Returns the Levenshtein distance between the current String and the specified String. indexOf String subString Integer Returns the index of the first occurrence of the specified substring. insertion or substitution).Black&. i). The Levenshtein distance is the number of changes needed to change one String into another.<. so this method returns -1.".assertEquals( -1.Reference Apex Primitive Methods Name Arguments Return Type Description System. result). String s2 = 'xc'.indexOf(myString2. result). If none of the characters occur.assertEquals( 0. result). String s2 = 'abxc'. result). returns -1. indexOfAny String substring Integer Returns the zero-based index of the first occurrence of any character specified in the substring. System. If the 310 . Integer result = myString1. indexOfAnyBut String substring Integer Returns the zero-based index of the first occurrence of a character that is not in the specified substring. System. System. indexOfDifference String s Integer Returns the zero-based index of the character where the current String begins to differ from the specified String. Example: String s1 = 'abcd'. 0). Otherwise.assertEquals( 2.indexOfDifference(s2).assertEquals( 2.Reference Apex Primitive Methods Name Arguments Return Type Description substring does not occur. Example: String s1 = 'abcd'. String myString2 = 'bc'. indexOfIgnoreCase String substring Integer Returns the zero-based index of the first occurrence of the specified substring without regard to case. this method returns -1. String s2 = 'xc'.assertEquals(1. For example: String myString1 = 'abcd'.indexOfAny(s2). System. Example: String s1 = 'abcd'. Integer result = s1.indexOfAnyBut(s2). Integer result = s1. Integer result = s1. returns -1. assertEquals( false. String s2 = 'BC'. Returns true if all characters in the current String are uppercase.assertEquals( isAlphanumeric 311 . result).isAlphanumeric().isAlpha(). b1).assertEquals( true. Returns true if all characters in the current String are lowercase. this method returns -1. // Returns true Boolean b1 = s1. // Returns false Boolean b2 = s2.indexOfIgnoreCase(s2. Returns true if all characters in the current String are Unicode letters only. otherwise. otherwise. Example: // Letters only String s1 = 'abc'. Integer result = s1. System. System. System. indexOfIgnoreCase String substring Integer Integer startPosition Returns the zero-based index of the first occurrence of the specified substring from the point of index i. returns false. without regard to case. otherwise. b2). If the substring does not occur. isAllLowerCase Boolean Boolean Boolean isAllUpperCase isAlpha isAlphaSpace Boolean Boolean Returns true if all characters in the current String are Unicode letters or spaces only. For example: String s1 = 'abcd'. otherwise.Reference Apex Primitive Methods Name Arguments Return Type Description substring does not occur. returns false. Returns true if all characters in the current String are Unicode letters or numbers only. System. Example: // Letters only String s1 = 'abc'. 0). // Letters and numbers String s2 = 'abc 21'. // Returns true Boolean b1 = s1.assertEquals(1.isAlpha(). this method returns -1. returns false. otherwise. returns false. returns false. i1). // Returns true Boolean b2 = s2. lastIndexOf lastIndexOf String substring Integer endPosition Integer 312 . If endPosition is larger than the last index in the current String. 7). numbers. i2). Integer i2 = s1. returns false. isAsciiPrintable Boolean Boolean isNumeric isNumericSpace Boolean Returns true if the current String contains only Unicode digits or spaces. otherwise. starting from the character at index 0 and ending at the specified index.assertEquals( true. this method returns -1. System. // Letters and numbers String s2 = 'abc021'. returns false. otherwise. otherwise.2) is not a Unicode digit. otherwise. returns false. returns false. A decimal point (1. this method returns -1.lastIndexOf('c'. 3).Reference Apex Primitive Methods Name Arguments Return Type Description true.2) is not a Unicode digit.isAlphanumeric(). or spaces only. b2). Returns the index of the last occurrence of the specified substring. the entire String is searched. isWhitespace Boolean String substring Integer Returns true if the current String contains only white space characters. If the substring doesn’t occur or endPosition is negative. System.lastIndexOf('c'. returns false. isAlphanumericSpace Boolean Returns true if all characters in the current String are Unicode letters. System. Returns true if the current String contains only ASCII printable characters. Returns true if the current String contains only Unicode digits. If the substring does not occur. A decimal point (1. b1).assertEquals( 2. Integer i1 = s1. otherwise.assertEquals( 6. Returns the index of the last occurrence of the specified substring. Example: String s1 = 'abcdaacd'. If the substring doesn’t occur. Integer i1 = s1.left(3). System. Example: String s1 = 'abc'. i1). Integer i1 = s1.lastIndexOfIgnoreCase('C'. If endPosition is larger than the last index in the current String.assertEquals( 3. String s2 = 313 . Example: String s1 = 'abcdaacd'. this method returns -1. the entire String is searched. 7). System. the entire String is returned. the entire String is returned without space padding. left Integer length String Returns the leftmost characters of the current String of the specified length. starting from the character at index 0 and ending at the specified index. String s2 = s1. If length is less than or equal to the current String size. leftPad Integer length String Returns the current String padded with spaces on the left and of the specified length. Example: String s1 = 'abcdaacd'. If the substring doesn’t occur or endPosition is negative. Example: String s1 = 'abcdaacd'.Reference Apex Primitive Methods Name Arguments Return Type Integer Description Returns the index of the last occurrence of the specified substring regardless of case. this method returns -1. lastIndexOfIgnore String substring Case lastIndexOfIgnore String substring Case Integer Integer endPosition Returns the index of the last occurrence of the specified substring regardless of case. i1). s2).lastIndexOfIgnoreCase('DAAC').assertEquals( 6. System. If length is greater than the String size.assertEquals( 'abc'. s2). If length is greater than the remaining characters. For example: String myString = 'abcd'. System. and repeating white space characters removed. s2). an empty String is returned. System. This method is similar to the substring(startIndex) and substring(startIndex.assertEquals(result. If length is negative or zero.com'. String s2 = s1. System. endIndex) methods. If startIndex is negative. s2). Integer result = myString. This method is based on its counterpart normalizeSpace method in the Apache Commons Lang StringUtils library. System. trailing. length Integer Returns the number of 16-bit Unicode characters contained in the String.mid(2. 4).assertEquals( ' abc'. 314 .normalizeSpace().length().assertEquals( 'cde'. it is considered to be zero.assertEquals( 'Salesforce force.com'. the remainder of the String is returned. normalizeSpace String Returns the current String with leading.leftPad(5). String s2 = s. except that the second argument is the number of characters to return. Example: String s = 'abcde'.Reference Apex Primitive Methods Name Arguments Return Type Description s1. 3). Example: String s1 = 'Salesforce \t force. mid Integer startIndex String Integer length Returns a new String that begins with the character at the specified zero-based startIndex with the number of characters specified by length. System. s2).removeEndIgnoreCase('. s2).assertEquals( 'force and force. removeStartIgnore String substring Case String Removes the specified substring only if it occurs at the beginning of the String using a case-insensitive match. removeEndIgnoreCase String substring String Removes the specified substring only if it occurs at the end of the String using a case-insensitive match. Example: String s1 = 'Salesforce and force. System.assertEquals( 'Sales and .removeEnd('. Example: String s1 = 'Salesforce and force. System. Example: String s1 = 'Salesforce and force.removeStart('Sales'). String s2 = s1.com'.com').remove('force').Reference Apex Primitive Methods Name remove Arguments String substring Return Type String Description Removes all occurrences of the specified substring and returns the String result.com'.com'. Example: String s1 = 'Salesforce and force. String s2 = s1. s2).com'. Example: String s1 = 'Salesforce and force.assertEquals( 'Salesforce and force'. removeEnd String substring String Removes the specified substring only if it occurs at the end of the String.com'. s2).assertEquals( 'force and force.com'.assertEquals( 'Salesforce and force'. removeStart String substring String Removes the specified substring only if it occurs at the beginning of the String.removeStartIgnoreCase('SALES'). s2). System.COM').com'. 315 . String s2 = s1. String s2 = s1.com'. System. String s2 = s1. the entire String is returned. Returns the rightmost characters of the current String of the specified length. System. s2). String s2 = s1. Replaces the first substring of a string that matches the regular expression regExp with the replacement sequence replacement. See the Java Pattern class for information on regular expressions. Returns a String with all the characters reversed. See the Java Pattern class for information on regular expressions. If length is greater than the String size.right(3). s2).assertEquals( 'SFDCSFDC'. String s2 = s1. 2). String s2 = s1. replace String target String replacement String Replaces each substring of a string that matches the literal target sequence target with the specified literal replacement sequence replacement. Example: String s1 = 'Hello Max'.Reference Apex Primitive Methods Name repeat Arguments Integer numTimes Return Type String Description Returns the current String repeated the specified number of times.assertEquals( 'SFDC-SFDC'.repeat('-'. Example: String s1 = 'SFDC'. Replaces each substring of a string that matches the regular expression regExp with the replacement sequence replacement. repeat String separator Integer numTimes String Returns the current String repeated the specified number of times using the specified separator to separate the repeated Strings.assertEquals( 'Max'. s2). System.repeat(2). System. replaceAll String regExp String replacement String replaceFirst String regExp String replacement String reverse right String Integer length String 316 . Example: String s1 = 'SFDC'. for String s = 'boo:and:foo': • • • • s.split(':'. 'foo'} s. The substrings are placed in the list in the order in which they occur in the String. and trailing empty strings are discarded. If regExp does not match any part of the String.rightPad(5). 'foo'} s. If limit is non-positive then the pattern is applied as many times as possible and the list can have any length. 'and'. ''. the pattern is applied at most limit . the list can have any length. or the end of the String. the list's length is no greater than limit.split('o'. 2) results in {'boo'. The optional limit parameter controls the number of times the pattern is applied and therefore affects the length of the list: • If limit is greater than zero. the entire String is returned without space padding. If length is less than or equal to the current String size. -2) results in {'boo'. 'and:foo'} s. 'and'. If limit is zero then the pattern is applied as many times as possible. Example: String s1 = 'abc'.assertEquals( 'abc '. See the Java Pattern class for information on regular expressions. 5) results in {'b'. ':and:f'. String s2 = s1. the resulting list has just one element containing the original String.split(':'. 5) results in {'boo'. ''} 317 . s2). ''. • • For example. split String regExp Integer limit String[] Returns a list that contains each substring of the String that is terminated by the regular expression regExp.split(':'. and the list's last entry contains all input beyond the last matched delimiter. System.Reference Apex Primitive Methods Name rightPad Arguments Integer length Return Type String Description Returns the current String padded with spaces on the right and of the specified length.1 times. split('o'. 0) results in {'b'.com platform'. List<String> ls = s1. -2) results in {'b'. ''.lang. . System. see java. with the following exception: the uppercase character.. . ''. platform) startsWith String prefix String prefix Boolean Boolean Returns true if the String that called the method begins with the specified prefix.getType(char). orce.debug(ls). ':and:f'.lang. System.getType(char). see java. For more information about the character types used.split('o'. immediately preceding a lowercase character token belongs to the following character token rather than to the preceding. ''} s. ''.Reference Apex Primitive Methods Name Arguments Return Type Description • • s. List<String> ls = s1.splitByCharacterType(). ':and:f'} See also Splitting String Example.. platform) splitByCharacterType CamelCase List<String> Splits the current String by character type and returns a list of contiguous character groups of the same type as complete tokens. splitByCharacterType List<String> Splits the current String by character type and returns a list of contiguous character groups of the same type as complete tokens. Example: String s1 = 'Force.Character. // Writes this output: // (F. . Example: String s1 = 'Force. com.debug(ls). // Writes this output: // (Force. if any.com platform'. Returns true if the current String begins with the specified prefix regardless of the prefix case. startsWith IgnoreCase substring Integer startIndex String 318 . . com.splitByCharacterTypeCamelCase().Character. Returns a new String that begins with the character at the specified zero-based startIndex and extends to the end of the String. For more information about the character types used. assertEquals( 'Force'. substringAfterLast String separator String Returns the substring that occurs after the last occurrence of the specified separator.platform'.substringBeforeLast('.substringAfterLast('.substringAfter('.com. Example: String s1 = 'Force.Reference Apex Primitive Methods Name substring Arguments Return Type Description Returns a new String that begins with the character at the specified zero-based startIndex and extends to the character at endIndex .platform'. substringBeforeLast String separator String Returns the substring that occurs before the last occurrence of the specified separator.com.').substring(1. s2).').assertEquals( 'Force. Example: String s1 = 'Force.platform'. System.com. Example: String s1 = 'Force. System.1. System.substring(4.platform'. s2). 5). // Returns "urge" 'smiles'. s2).'). Example: String s1 = 'Force.platform'. String s2 = s1.com. s2). substringBefore String separator String Returns the substring that occurs before the first occurrence of the specified separator. // Returns "mile" Integer startIndex String Integer endIndex substringAfter String separator String Returns the substring that occurs after the first occurrence of the specified separator.substringBefore('.'). String s2 = s1. 319 . System. String s2 = s1. 8). For example: 'hamburger'. String s2 = s1.assertEquals( 'platform'.com'.assertEquals( 'com. com'. String s2 = s1. toLowerCase toUpperCase 320 .COM'. System.assertEquals( 'Yellow'.substringBetween('tag'). Converts all of the characters in the String to lowercase using the rules of the specified locale. true).swapCase(). String myString2 = 'ABCD'. Example: String s1 = 'Force. s2). s2).substringBetween('x'. swapCase String open String close String Swaps the case of all characters and returns the resulting String. substringBetween String tag substringBetween String open String String close Returns the substring that occurs between the two specified Strings.Reference Apex Primitive Methods Name Arguments Return Type String Description Returns the substring that occurs between two instances of the specified String. myString1 = myString1. toLowerCase String String locale String String Converts all of the characters in the String to lowercase using the rules of the default locale. s2). Upper case and title case converts to lower case. System.'y'). System.equals(myString2).assertEquals( 'fORCE.toUpperCase(). Example: String s1 = 'tagYellowtag'. Converts all of the characters in the String to uppercase using the rules of the default locale. and lower case converts to upper case. Example: String s1 = 'xYellowy'. String s2 = s1.assertEquals( 'Yellow'. Boolean result = myString1. System. String s2 = s1. For example: String myString1 = 'abcd'.assertEquals(result. Returns a copy of the string that no longer contains any leading or trailing white space characters. String s2 = s1. This method is based on its counterpart unescapeCsv method in the Apache Commons Lang StringEscapeUtils library.unescapeCsv(). newline or double quote. Also. Example: String s1 = '"Max1. s2). String s2 = s1. System. Example: String s1 = 'Hello max'. Leading and trailing ASCII control characters such as tabs and newline characters are also removed. or is and does not contain a comma. ""Max2"""'.Reference Apex Primitive Methods Name toUpperCase Arguments String locale Return Type String String Description Converts all of the characters in the String to the uppercase using the rules of the specified locale. s2). newline or double quote.assertEquals( 'Max1. unescapeCsv String Returns a String representing an unescaped CSV column. trim uncapitalize String Returns the current String with the first letter in lowercase. 321 . it is returned unchanged. any double quote escaped characters (a pair of double quotes) are unescaped to just one double quote. If the String is not enclosed in double quotes.assertEquals( 'hello max'.uncapitalize(). If the String is enclosed in double quotes and contains a comma. White space and control characters that aren’t at the beginning or end of the sentence aren’t removed. System. "Max2"'. quotes are removed. s2).unescapeHtml3(). s2).unescapeHtml4(). System."3.". String s2 = s1. String s2 = s1. String s2 = s1.Black&.White>.8\". This method is based on its counterpart unescapeHtml3 method in the Apache Commons Lang StringEscapeUtils library.Black&.assertEquals( '"<Black&White>"'. Example: String s1 = '". 322 . This method is based on its counterpart unescapeEcmaScript method in the Apache Commons Lang StringEscapeUtils library. System.'. This method is based on its counterpart unescapeHtml4 method in the Apache Commons Lang StringEscapeUtils library.0 entities.unescapeEcmaScript(). Example: String s1 = '\"3. System. s2). unescapeHtml4 String Unescapes the characters in a String using HTML 4.assertEquals( '"3.9\"'.Reference Apex Primitive Methods Name unescapeEcmaScript Arguments Return Type String Description Unescapes any EcmaScript literals found in the String.assertEquals( '"<Black&White>"'.<.8".'.\"3.9"'.0 entities. Example: String s1 = '".". unescapeHtml3 String Unescapes the characters in a String using HTML 3.<.White>. seconds. a string is split.getInstance(). The following example creates a time of 18:30:2:20: Time myTime = Time.csv')). List<String> parts = filename.assertEquals( '"<Black&White>"'.". return filename.assertEquals('PPDSF100111. s2). Example: String s1 = '". 323 . For more information on Strings.newInstance(18. Supports only the five basic XML entities (gt.'.csv'. String s2 = s1.split('\\\\'). Does not support DTDs or external entities. System. removePath('e:\\processed\\PPDSF100111. 2. using a backslash as a delimiter: public String removePath(String filename) { if (filename == null) return null. see Primitive Data Types on page 26. Name newInstance Arguments Integer hour Integer minutes Integer seconds Integer milliseconds Return Type Time Description Constructs a Time from Integer representations of the hour.unescapeXml(). 30. This method is based on its counterpart unescapeXml method in the Apache Commons Lang StringEscapeUtils library.Reference Apex Primitive Methods Name unescapeXml Arguments Return Type String Description Unescapes the characters in a String using XML entities. 20). filename = parts[parts. and milliseconds. minutes.Black&. amp. quot. Splitting String Example In the following example.size()-1]. EmailUtilities.White>. } static testMethod void testRemovePath() { System. lt. apos). } Time Methods The following are the system static methods for Time.<. addHours(2). Returns the second component of a Time. see Primitive Data Types on page 26.newInstance(18. The collection methods are: • • • List Map Set Note: There is no limit on the number of items a collection can hold. 35). Integer myMinutes = myTime.assertEquals(myMinutes. myMinutes = myMinutes + 5. Returns the hour component of a Time. For more information on time. 30.assertEquals(myHour. retrieving. Returns the minute component of a Time. and manipulating the data.newInstance(18. there is a general limit on heap size. 20). 30. Integer myHour = myTime. Adds the specified number of addlMilliseconds to a Time. System. addMilliseconds Integer Time addlMilliseconds addMinutes Integer addlMinutes Time addSeconds Integer addlSeconds Time Integer Adds the specified number of addlSeconds to a Time. For example: Time myTime = Time.Reference Apex Collection Methods The following are the instance methods for Time. 324 .minute(). However.hour(). Name addHours Arguments Integer addlHours Return Type Time Description Adds the specified number of addlHours to a Time. myTime = myTime. 20). For example: Time myTime = Time. 2. Apex Collection Methods All the collections in Apex have methods associated with them for assigning. System. 20). hour millisecond minute second Integer Integer Integer Returns the millisecond component of a Time. 2. Adds the specified number of addlMinutes to a Time. add(0.add(47). That is. Note that the set and the list must be of the same type. consequently setting the list's length to zero.assertEquals(myList. the duplicate list will only be a shallow copy of the list.add(1. 47). 47). In the following example. For example: List<Integer> myList = new List<Integer>().clear(). List_elem represents a single element of the same type as the list. For example. Add all of the elements in set s to the list that calls the method. that is. List<Integer> myList = new Integer[6]. Note that both lists must be of the same type. myList.get(0). Name add Arguments Any type e Return Type Void Description Adds an element e to the end of the list. 52).Reference Apex Collection Methods List Methods The list methods are all instance methods. add Integer i Any type e Void Inserts an element e into the list at index position i. addAll Set s Void clear Void clone List (of same type) Makes a duplicate copy of a list. the list that calls it is its implicit parameter. myList.get(1). 52). a list with six elements is created. Note that if this is a list of sObject records. myList. the duplicate will have references to each 325 . Even though the clear method does not include any parameters. the following removes all elements from myList: myList.assertEquals(myNumber. The following are the instance parameters for List. Removes all elements from a list. they operate on a particular instance of a list. Integer myNumber = myList. and integers are added to the first and second index positions. system. system. addAll List l Void Adds all of the elements in list l to the list that calls the method. Note: In the table below. The optional opt_preserve_id argument determines whether the IDs of the original objects are preserved or cleared in the duplicates. 'San Francisco'). Account b = new Account( Name='Salesforce').assertEquals( q2[0]. Account b = new Account(). q1[0]. For example: Account a = new Account(Name='Acme'. System. If set to 326 . Account[] q2 = q1. not with lists of primitives.assertEquals( q2[0]. q1[0]. but the sObject records themselves will not be duplicated.b}.Reference Apex Collection Methods Name Arguments Return Type Description object. Boolean opt_preserve_autonumber Note: deepClone only works with lists of sObjects. System. For example: Account a = new Account(Name='Acme'. BillingCity='New York'). System.assertEquals( q1[0]. BillingCity='New York').deepClone(). Account[] q1 = new Account[]{a.assertEquals( q1[0].BillingCity.BillingCity.BillingCity = 'San Francisco'.clone().BillingCity. System. To also copy the sObject records. Account[] q2 = q1.BillingCity. 'San Francisco'). 'San Francisco'). type) including the sObject records themselves.b}. Account[] q1 = new Account[]{a. you must use the deepClone method. deepClone Boolean opt_preserve_id Boolean opt_preserve_readonly_timestamps List (of same object Makes a duplicate copy of a list of sObject records.BillingCity = 'San Francisco'. 'New York'). Reference Apex Collection Methods Name Arguments Return Type Description true. If set to true.CreatedDate. LastModifiedById. that is. CreatedDate. LastModifiedDate. insert q1. The optional opt_preserve_autonumber argument determines whether the autonumber fields of the original objects are preserved or cleared in the duplicates. the values are cleared. auto number fields are cleared. that is.assertEquals( q3[0]. the IDs are cleared.CreatedById. System.deepClone(false.false). the IDs are preserved. System. // Clone list while preserving // timestamp and user ID fields. LastModifiedById. the read-only fields CreatedById. // Verify timestamp fields are // preserved for the first // list element. If set to true. 327 . CreatedDate. accts[0]. BillingCity FROM Account WHERE Name='Acme' OR Name='Salesforce']. that is. The optional opt_preserve_readonly_timestamps argument determines whether the read-only timestamp and user ID fields are preserved or cleared in the duplicates. This example is based on the previous example and shows how to clone a list with preserved read-only timestamp and user ID fields.true. the default value for the opt_preserve_id argument is true.assertEquals( q3[0]. List<Account> accts = [SELECT CreatedById. auto number fields are copied to the cloned objects. the IDs are copied to the cloned objects.com API version 22. The default is false.CreatedDate). The default is false. The default is false. and LastModifiedDate are copied to the cloned objects. accts[0]. Account[] q3 = accts. that is.0 or earlier. Note: For Apex saved using Salesforce.CreatedById). To make a shallow copy of a list without duplicating the sObject records it contains. Integer myNumber = myList. colors[0] = 'Red'.query ('SELECT Id FROM Account ' + 'LIMIT 1'). For example: List<String> colors = new String[3]. you can also follow the name of the list with the element's index position in square brackets.SObjectType Returns the token of the sObject type that makes up a list of sObjects.assertEquals(myNumber. accts[0]. 328 . use the clone method. get Integer i Array element Returns the list element stored at index i. colors[1] = 'Blue'. For example: Account a = new Account(name='test'). colors[2] = 'Green'.assertEquals( s. System.LastModifiedById). accts[0].assertEquals( q3[0]. For example.LastModifiedDate).LastModifiedDate.getSObjectType().Reference Apex Collection Methods Name Arguments Return Type Description System. List<Integer> myList = new List<Integer>(). 47). // Verify if that sObject // variable is // an Account token System. myList. Use this with describe information to determine if a list contains sObjects of a particular type.sObjectType). insert a. Account. getSObjectType Schema.get(0). To reference an element of a one-dimensional list of primitives or sObjects.LastModifiedById. // Create a list of // generic sObjects List<sObject> q = new Account[]{}. // Create a generic sObject // variable s SObject s = Database. system.add(47).assertEquals( q3[0]. } else { return true.getSObjectType().} public CustomIterable(){ accs = [SELECT Id. Name.sObjectType). 329 . } } Note: You do not have to implement the iterable interface to use the iterable methods with a list. return accs[i-1]. For more information.} i++. From the iterator. } } global // // // // Account next(){ 8 is an arbitrary constant in this example that represents the maximum size of the list. For example: global class CustomIterable implements Iterator<Account>{ List<Account> accs {get. i = 0. } global boolean hasNext(){ if(i >= accs.assertEquals( q. NumberOfEmployees FROM Account WHERE Name = 'false']. Account. set. isEmpty iterator Boolean Iterator Returns true if the list has zero elements Returns an instance of an iterator. see Understanding Apex Describe Information on page 163.Reference Apex Collection Methods Name Arguments Return Type Description // Verify if the list of // sObjects // contains Account tokens System.size()) { return false. you can use the iterable methods hasNext and next to iterate through the list.} Integer i {get. Note that this method can only be used with lists that are composed of sObjects. set. if(i == 8){return null. the list has three elements.size(). 6). In the following example. system.set(0. For example: List<Integer> myList = new Integer[6]. myList. For example: List<String> colors = new String[3]. size Integer Returns the number of elements in the list.assertEquals(size2. colors[2] = 'Green'. 52).Reference Apex Collection Methods Name remove Arguments Integer i Return Type Array element Description Removes the element that was stored at the ith index of a list.assertEquals(size. sort Void Sorts the items in the list in ascending order. myList. colors[1] = 'Blue'. 330 .size(). When the list is sorted. For example: List<Integer> myList = new List<Integer>(). system. 52). colors[0] = 'Red'. List<Integer> myList2 = new Integer[6]. colors[2] = 'Green'. colors[1] = 'Blue'. 'Green').set(1.assertEquals(S1. colors[0] = 'Red'. 0). 47). Integer size = myList.assertEquals(myList. you can also follow the name of the list with the element's index position in square brackets. String S1 = colors. To set an element of a one-dimensional list of primitives or sObjects.get(1). For example: List<String> colors = new String[3]. the first element is null because it has no value assigned while the second element has the value of 5: List<Integer> q1 = new Integer[3].remove(2). system. system. returning the element that was removed. set Integer i Any type e Void Assigns e to the position at list index i. Integer size2 = myList2. 5). Two keys that differ only by the case are considered unique and have corresponding distinct Map entries. Uniqueness of map keys of user-defined types is determined by the equals and hashCode methods. the Map methods. q1[1] = 5. see List Sorting. second is 5 system. user-defined types.get(1). which can be any data type—primitive types. The following are the instance methods for maps. Map (of same type) Makes a duplicate copy of the map. For more information on the sort order used for sObjects. Uniqueness of all other non-primitive types is determined by comparing the objects’ fields. but the records themselves are not duplicated. Note: • • • In the table below. For example: Account a = new Account( Name='Acme'. you can sort primitive types. they operate on a particular instance of a map. which you provide in your classes. get. q1. Note: Using this method. see Lists on page 33. 331 . You can also sort custom types (your Apex classes) if they implement the Comparable interface.sort(). Note that if this is a map with sObject record values. the duplicate will have references to each sObject record. SelectOption elements. That is. Name clear clone Arguments Return Type Void Description Removes all of the key-value mappings from the map. Key_type and Value_type represent the data type of the map key and value respectively. that is. Map keys of type String are case-sensitive. and remove treat these keys as distinct. and built-in Apex types. Map Methods The map methods are all instance methods. // First element is null.Reference Apex Collection Methods Name Arguments Return Type Description // Assign values to the first // two elements q1[0] = 10. the duplicate map will only be a shallow copy of the map. including put. collections. sObjects.assertEquals(q1. and sObjects (standard objects and custom objects). containsKey. Subsequently. For more information on lists. String>(). colorCodes. Account> map1 = new Map<Integer. containsKey Key type key Boolean Returns true if the map contains a mapping for the specified key. BillingCity. Map<Integer.get(1). Map<Integer. To also copy the sObject records. 'San Francisco'). string> colorCodes = new Map<String. Account> {}. colorCodes.Reference Apex Collection Methods Name Arguments Return Type Description BillingCity='New York'). you must use the deepClone method. True). including sObject records if this is a map with sObject record values.assertEquals(map1. map1.containsKey('Blue'). If the key is a string.put('Red'. 'San Francisco'). a).deepClone(). map1.BillingCity. Account> map2 = map1.assertEquals(contains. 'FF0000'). BillingCity='New York'). map1.BillingCity = 'San Francisco'. Account> map2 = map1.assertEquals( map1.get(1). map1. For example: Account a = new Account( Name='Acme'.assertEquals( map2. For example: Map<string.get(1). a). Account> {}. Map<Integer.get(1).put(1.BillingCity.put('Blue'.get(1). deepClone Map (of the same type) Makes a duplicate copy of a map.BillingCity = 'San Francisco'.put(1. System. Account> map1 = new Map<Integer. 332 . System. the key value is case-sensitive. Map<Integer. '0000A0'). System.clone(). Boolean contains = colorCodes. System. 'San Francisco'). For example: Map<String. Use this with describe information. 'FF0000'). '0000A0'). '0000A0').assertEquals( s.put('Blue'. String> colorCodes = new Map<String. // Create a map of generic // sObjects Map<Integer.get('Blue'). If the key is a string.sObjectType). BillingCity. String code = colorCodes.get('Magenta').assertEquals(map2.put('Red'. Account>(). // The following is not a color // in the map String code2 = colorCodes. the key value is case-sensitive. insert a.get(1). String>(). // Verify if the list of sObjects 333 .assertEquals(code. System. get Key type key Value_type Returns the value to which the specified key is mapped.getSObjectType(). System.Reference Apex Collection Methods Name Arguments Return Type Description System. Account> M = new Map<Integer. or null if the map contains no value for this key. // Verify if that sObject // variable // is an Account token System. Account.query ('SELECT Id FROM Account ' + 'LIMIT 1'). 'New York'). getSObjectType Schema.assertEquals(code2. For example: Account a = new Account( Name='Acme'). to determine if a map contains sObjects of a particular type. To make a shallow copy of a map without duplicating the sObject records it contains. use the clone() method. colorCodes. // Create a generic sObject // variable s SObject s = Database.SObjectType Returns the token of the sObject type that makes up the map values. null). colorCodes. colorCodes. '#FF0000'). Set <String> colorSet = new Set<String>(). see Understanding Apex Describe Information on page 163. Note that this method can only be used with maps that have sObject values. For more information.put('Blue'. colorSet = colorCodes. If the map is of IDs or Strings to sObjects.assertEquals( M. '0000A0').put('Red'. String>(). 'FF0000'). String>(). Boolean empty = colorCodes. colorCodes.keySet(). 'ff0000'). the old value is returned by the method and then replaced.assertEquals(empty. Value value Value_type Associates the specified value with the specified key in the map.put('Red'. put Key key. String> colorCodes = new Map<String.getSObjectType(). colorCodes.Reference Apex Collection Methods Name Arguments Return Type Description // contains Account tokens System. String> colorCodes = new Map<String. For example: Map<String. If the key is a string. For example: Map<String. isEmpty Boolean Returns true if the map has zero key-value pairs.put('Red'. colorCodes. keySet Set of Key_type Returns a set that contains all of the keys in the map. If the map previously contained a mapping for this key.sObjectType). the key value is case-sensitive. true). For example: Map<String. Account. system.isEmpty(). String>(). String> colorCodes = new Map<String. The new mappings from m replace any mappings that the original map had. // Red is now #FF0000 putAll Map m Void Copies all of the mappings from the specified map m to the original map. putAll sObject[] l 334 . adds the list of sObject records l to the map in the same way as the Map constructor with this input. String>(). colorCodes.values().put('Blue'.get('Blue'). System. A set contains only unique elements and doesn’t have duplicate values.put('Red'. List<String> colors = new List<String>(). For example: Map<String. the key value is case-sensitive. 'FF0000'). 2). sObjects.size(). 335 . an unordered collection of elements that was initialized using the set keyword. Set methods are all instance methods. collections. colorCodes. String myColor = colorCodes.assertEquals(code2. size Integer Returns the number of key-value pairs in the map. colorCodes. user-defined types. colorCodes.Reference Apex Collection Methods Name remove Arguments Key key Return Type Value_type Description Removes the mapping for this key from the map if it is present. that is. 'FF0000').put('Red'. The value is returned by the method and then removed. Set Methods The Set methods work on a set. For more information on maps. String> colorCodes = new Map<String. that is. String>(). String code2 = colorCodes. The following are the instance methods for sets. 'FF0000').put('Red'.put('Blue'. For example: Map<String. Set elements can be of any data type—primitive types. colorCodes. they all operate on a particular instance of a Set. colors = colorCodes. '0000A0'). String> colorCodes = new Map<String. see Maps on page 40. system.assertEquals(mSize.remove('Blue'). String> colorCodes = new Map<String. colorCodes. '0000A0'). null). If the key is a string. String>(). For example: Map<String. and built-in Apex types. '0000A0').put('Blue'. values list of Value_type Returns a list that contains all of the values in the map in arbitrary order. Integer mSize = colorCodes. system. For example: set<string> myString = new Set<String>{'a'. true). which you provide in your classes. This method returns true if the original set changed as a result of the call. This method results in the union of the list and the set. This method returns true if the original set changed as a result of the call.Reference Apex Collection Methods Note: • • In the table below. Boolean result1. The list must be of the same type as the set that calls the method.assertEquals(result. Boolean result. addAll List l Boolean Adds all of the elements in the specified list to the set if they are not already present. result = myString. clear clone Void Set (of same type) Removes all of the elements from the set Makes a duplicate copy of the set 336 . The specified set must be of the same type as the original set that calls the method. Uniqueness of set elements of user-defined types is determined by the equals and hashCode methods. This method results in the union of the two sets. the elements are case-sensitive. 'c'}. true).addAll(sString). This method returns true if the original set changed as a result of the call. 'b'. If the set contains String elements.add('d').assertEquals(result1. addAll Set s Boolean Adds all of the elements in the specified set to the set that calls the method if they are not already present. Uniqueness of all other non-primitive types is determined by comparing the objects’ fields. For example: set<string> myString = new Set<String>{'a'. 'b'}. Set_elem represents a single element in the set. Two set elements that differ only by case are considered distinct. system. • Name add Arguments Set element e Return Type Boolean Description Adds an element to the set if it is not already present. set<string> sString = new Set<String>{'c'}. result1 = myString. This method returns true if the original set changed as a result of the call. 337 . set<string> rString = new Set<String>{'a'.assertEquals(result2.assertEquals(result. true). 'c'}. system.Reference Apex Collection Methods Name contains Arguments Set element e Return Type Boolean Description Returns true if the set contains the specified element. Boolean result. result = myString. system.containsAll(rString). Boolean result. 'b'. true). This method results in the relative complement of the two sets. remove Set Element e Boolean Removes the specified element from the set if it is present. system. 'b'}.isEmpty(). For example: Set<integer> mySet = new Set<integer>(). For example: set<string> myString = new Set<String>{'a'. removeAll List l Boolean Removes the elements in the specified list from the set if they are present. set<string> sString = new Set<String>{'c'}. 'b'}. Boolean result1. Returns true if the set contains all of the elements in the specified set.contains('z'). system. false). containsAll List l Boolean Returns true if the set contains all of the elements in the specified list.assertEquals(result. The list must be of the same type as the set that calls the method. result1 = myString. containsAll Set s Boolean isEmpty Boolean Returns true if the set has zero elements. result2.assertEquals(result1. The list must be of the same type as the set that calls the method. result2 = myString. result = mySet. true). The specified set must be of the same type as the original set that calls the method.addAll(sString). For example: set<string> myString = new Set<String>{'a'. System. For example: Set<integer> mySet = new Set<integer>{1.Reference Apex Collection Methods Name Arguments Return Type Description This method returns true if the original set changed as a result of the call. 1). 2. 2. System. This method results in the intersection of the two sets. Boolean result = mySet. This method results in the intersection of the list and the set. This method returns true if the original set changed as a result of the call. 338 . This method results in the relative complement of the two sets.assertEquals(result2. The specified set must be of the same type as the original set that calls the method. This method returns true if the original set changed as a result of the call.retainAll(myList). For example: Set<integer> mySet = new Set<integer>{1. Boolean result = mySet. retainAll List l Boolean Retains only the elements in this set that are contained in the specified list.removeAll(myList). The specified set must be of the same type as the original set that calls the method. 3}.size(). Integer result2 = mySet. List<integer> myList = new List<integer>{1. System. true). This method returns true if the original set changed as a result of the call. 3}. true). The list must be of the same type as the set that calls the method. 3}. retainAll Set s Boolean Retains only the elements in the original set that are contained in the specified set. List<integer> myList = new List<integer>{1. removeAll Set s Boolean Removes the elements in the specified set from the original set if they are present. 3}.assertEquals(result.assertEquals(result. DELETE_FAILED. For more information about Enum. For more information on sets. true). In addition. Enum has the following method.assertEquals(result. For example: Integer i = StatusCode.assertEquals(result2. System. see Enums on page 44.size(). 339 .Reference Enum Methods Name size Arguments Return Type Integer Description Returns the number of elements in the set (its cardinality).DELETE_FAILED. 3}. Integer result2 = mySet. have the following methods defined in Apex: Name name ordinal Return Type String Integer Description Returns the name of the Enum item as a String. Boolean result = mySet. 2. 3}. all Enum values. List<integer> myList = new List<integer>{1. For example: Set<integer> mySet = new Set<integer>{1. 2). see Sets on page 38. System.name(). starting with zero. List<StatusCode> values = StatusCode.ordinal(). Enum Methods Although Enum values cannot have user-defined methods added to them. String s = StatusCode. including system Enum values.retainAll(myList). Returns the position of the item in the list of Enum values. Name values Return Type List<Enum type> Description Returns the values of the Enum as a list of the same Enum type.values(). Name getGlobalDescribe Arguments Return Type Map<String. see Accessing All sObjects on page 166. The following Apex sObject methods include methods that can be used with every sObject. You can specify one of the following sObjectNames: • KnowledgeArticleVersion—to retrieve category groups associated with article types. as well as more general classes used to describe sObject structures: • • • • • • Schema sObject sObject Describe Results Field Describe Results Schema. For more information. Schema. • Question—to retrieve category groups associated with questions. Schema.SObjectType> gd = Schema.Reference Apex sObject Methods Apex sObject Methods The term sObject refers to any object that can be stored in the Salesforce platform database. For example: Map<String.getGlobalDescribe().FieldSet Methods Custom Settings Schema Methods The following table lists the system methods for Schema.Describe List<sObjectNames> DataCategoryGroupResult> Returns a list of the category groups associated with the specified objects. describeDataCategory Groups String List<Schema. see Accessing All Data 340 . For more information and code examples using describeDataCategory Groups.SObjectType> Description Returns a map of all sObject names (keys) to sObject tokens (values) for the standard and custom objects defined in your organization. DataCategoryGroupSobjectTypePair> Specify one or more category groups and objects to query Schema. The following are the arguments for this method. Name pairs Return Type Description List<Schema. For more information on data category group visibility. see “About Category Group Visibility” in the Salesforce online help. Specify false to return all the visible parent and child categories. For more information on data category group visibility. Both values depend on the user's data category group visibility settings. describeDataCategory GroupStructures pairs. List<Schema. 341 . Describe Data Category Group Structure Arguments The describeDataCategory GroupStructures method returns the available category groups along with their data category structure. Visible data categories are retrieved for the specified object. For additional information and code examples using describeDataCategory GroupStructures. For additional information about articles and questions. see “About Category Group Visibility” in the Salesforce online help.Describe Returns available category topCategoriesOnly DataCategoryGroupStructureResult> groups along with their data category structure for objects specified in the request.DataCategoryGroupSobjectTypePair. see Accessing All Data Categories Associated with an sObject. topCategoriesOnly Boolean Specify true to return only the top visible category which classify the object. see “Managing Articles and Translations” and “Answers Overview” in the Salesforce online help.Reference Apex sObject Methods Name Arguments Return Type Description Categories Associated with an sObject. DataCategoryGroupSobjectTypePair specifies a category group and an associated object. It is used by the describeDataCategory GroupStructures method to return the categories available to this object. Name getCategoryCount getDescription getLabel getName Return Type Integer String String String Description Returns the number of visible data categories in the data category group Returns the description of the data category group Returns the label for the data category group used in the Salesforce user interface Returns the unique name used by the API to access to the data category group 342 . None of the methods take an argument. List<Schema.add('Question'). objType. The following table lists all the methods for Schema. The following is an example of how to instantiate a data category group describe result object: List <String> objType = new List<String>().add('KnowledgeArticleVersion').Reference Apex sObject Methods Schema.DataCategoryGroupSobjectTypePair Object Schema. Schema. For additional information and code examples using describeDataCategory Groups. objType.DataCategoryGroupSobjectTypePair.DescribeDataCategoryGroupResult Object The describeDataCategory Groups method returns a Schema. Name getDataCategoryGroupName getSobject setDataCategoryGroupName setSobject Arguments Return Type String String String Description Returns the unique name used by the API to access the data category group Returns the object name associated with the data category group Specifies the unique name used by the API to access the data category group The sObjectName is the object name associated with the data category group. The following table lists all the methods available as part of the data category group describe result. Question—for questions from Answers. see Accessing All Data Categories Associated with an sObject. Valid values are: • • KnowledgeArticleVersion—for article String sObjectName Void types.DescribeDataCategoryGroupResult> describeCategoryResult = Schema.DescribeDataCategoryGroupResult object containing the list of the category groups associated with the specified object.describeDataCategoryGroups(objType). Reference Apex sObject Methods Name getSobject Return Type String Description Returns the object name associated with the data category group Schema.setSobject('KnowledgeArticleVersion').DescribeDataCategoryGroupStructureResult object The describeDataCategory GroupStructures method returns a list of Schema. see Accessing All Data Categories Associated with an sObject. pairs. true). List<Schema. For additional information and code examples using describeDataCategory GroupStructures. that contains the top categories visible depending on the user's data category group visibility settings.setDataCategoryGroupName('Regions').DescribeDataCategoryGroupStructureResult>results = Schema. pair2.DataCategory> Description Returns the description of the data category group Returns the label for the data category group used in the Salesforce user interface Returns the unique name used by the API to access to the data category group Returns the name of object associated with the data category group Returns a Schema. pair1. None of the methods take an argument. The following is an example of how to instantiate a data category group structure describe result object: List <DataCategoryGroupSobjectTypePair> pairs = new List<DataCategoryGroupSobjectTypePair>(). The following table lists all the methods available as part of the data category group structure describe result.add(pair1). DataCategoryGroupSobjectTypePair pair2 = new DataCategoryGroupSobjectTypePair(). Name getDescription getLabel getName getSobject getTopCategories Return Type String String String String List<Schema. see “About Category Group Visibility” in the Salesforce online help. pair1.DataCategory object.Describe DataCategoryGroupStructureResult objects containing the category groups and categories associated with the specified object. 343 .setDataCategoryGroupName('Regions'). pairs.setSobject('Questions').add(pair2). pair2. For more information on data category group visibility. DataCategoryGroupSobjectTypePair pair1 = new DataCategoryGroupSobjectTypePair().describeDataCategoryGroupStructures(pairs. DataCategory object represents the categories within a category group. Name addError Arguments String errorMsg Return Type Void Description Marks a record with a custom error message and prevents any DML operation from occurring. The following table lists all the methods for the Schema.com API version 27.DataCategory object. they are called by and operate on a particular instance of an sObject. For more information. and on Trigger. the generated message is added to the collection of errors for the page. such as an account or contact. Name getChildCategories getLabel getName Return Type List<Schema. None of these methods take an argument.0 and later. The errorMsg argument is the error message to mark the record with.DataCategory> String String Description Returns a recursive object that contains the visible sub categories in the data category Returns the label for the data category used in the Salesforce user interface Returns the unique name used by the API to access to the data category sObject Methods sObject methods are all instance methods.old in before delete triggers. Note: For Apex saved using Salesforce. When used on Trigger. See Triggers and Trigger Exceptions. When used in Visualforce controllers. the error message is displayed in the application interface. The Schema. the specified error message is escaped in the Salesforce user interface.DataCategory Object A Schema. The following are the instance methods for sObjects. see 344 .DataCategory object is returned by the getTopCategories method. If the error message contains HTML markup.new in before insert and before update triggers. that is.Reference Apex sObject Methods Schema. the escaped markup displays as text and isn’t rendered in the user interface. the error message is displayed in the application interface. When used in Visualforce controllers. the generated message is added to the collection of errors for the page.Reference Apex sObject Methods Name Arguments Return Type Description Validation Rules and Standard Controllers in the Visualforce Developer's Guide. addError Exception exception Marks a record with a custom error message and prevents any DML operation from occurring.new in before insert and before update triggers. 345 . the escaped markup displays as text and isn’t rendered in the user interface. If the error message contains HTML markup.old in before delete triggers. and on Trigger. Note: • When used on Trigger. the specified error message is escaped in the Salesforce user interface.addError String errorMsg Void Places the specified error message on the field that calls this method in the application interface and prevents any DML operation from occurring. The exception argument is an Exception object or a custom exception object that contains the error message to mark the record with. the error appears in the application interface. For example: Trigger. and on Trigger.0 and later. see Validation Rules and Standard Controllers in the Visualforce Developer's Guide.old in before delete triggers. For more information.com API version 27. Note: For Apex saved using Salesforce.new in before insert and before update triggers.addError('bad').myField__C. See Triggers and Trigger Exceptions.new[0]. When used on Trigger. field. The default is false. Note: For Apex saved using Salesforce. type) Boolean opt_IsDeepClone The optional opt_preserve_id argument determines whether the ID of the original Boolean object is preserved or cleared in the duplicate. if there is an inputField component bound to field. This method is highly specialized because the field identifier is not actually the invoking object—the sObject record is the invoker. the ID opt_preserve_autonumber is cleared. the ID is preserved.Reference Apex sObject Methods Name Arguments Return Type Description • When used in Visualforce controllers. Note: For Apex saved using Salesforce.com API version 27.com API version 22. All fields on the 346 .0 and later. the message is attached to the component. see Validation Rules and Standard Controllers in the Visualforce Developer's Guide. or just a reference: • If set to true. The field is simply used to identify the field that should be used to display the error. This method will likely change in future versions of Apex. • • See Triggers and Trigger Exceptions. clear clone Void Boolean opt_preserve_id Clears all field values sObject (of same Creates a copy of the sObject record. For more information. the escaped markup displays as text and isn’t rendered in the user interface. that is. the method creates a full copy of the sObject.0 or earlier. the ID is copied to the Boolean duplicate. The optional opt_IsDeepClone argument determines whether the method creates a full copy of the sObject field. that is. opt_preserve_readonly_timestamps If set to true. the specified error message is escaped in the Salesforce user interface. the default value for the opt_preserve_id argument is true. If the error message contains HTML markup. CreatedDate. such as AccountNumber. The default is false. including relationship fields. Consequently. The optional opt_preserve_autonumber argument determines whether auto number fields of the original object are preserved or cleared in the duplicate. All copied relationship fields reference the original sObjects. For more information. get Schema. if you make changes to a relationship field on the cloned sObject. DMLOptions Returns the database. see Dynamic SOQL. For more information. the read-only fields CreatedById. and vice-versa. that is.sObjectField Field Object Returns the value for the field specified by the field token Schema.Account. the method performs a shallow copy of the sObject fields. getOptions Database. If set to true. Consequently. if you make changes to a field on the cloned sObject.sObjectField (for example. LastModifiedById. see Dynamic SOQL. The default is false. 347 . the corresponding field on the original sObject is also affected. If set to true. If set to false.Reference Apex sObject Methods Name Arguments Return Type Description sObject are duplicated in memory. the original sObject is not affected.DMLOptions object for the sObject. and LastModifiedDate are copied to the duplicate.AccountNumber). For more information. auto number fields are copied to the cloned object. that is. see Database DMLOptions Properties. • The optional opt_preserve_readonly_timestamps argument determines whether the read-only timestamp fields are preserved or cleared in the duplicate. the values are cleared. get String fieldName Object Returns the value for the field specified by fieldName. Schema. The default is false. auto number fields are cleared. For more information. see Understanding Apex Describe Information.SObjectField fieldName sObject Returns the value for the field specified by the field token Schema. Schema.sObjectField (for example. For more information. see Dynamic DML.AccountNumber) and returns the previous value for the field.Account.MyExternalId).Account.SObjectField fieldName Object Object value Sets the value for the field specified by the field token Schema. This method is primarily used with dynamic DML to access values for associated objects. such as child relationships.SObjectType fieldName sObject[] Returns the value for the field specified by the field token Schema. This method is primarily used with dynamic DML to access values for associated objects. put String fieldName Object value Object Sets the value for the field specified by fieldName and returns the previous value for the field. For more information. 348 . getSObjectType Schema.Contact). This method is primarily used with dynamic DML to access values for external IDs. getSObjects String fieldName sObject[] Returns the values for the field specified by fieldName. For more information. This method is primarily used with dynamic DML to access values for external IDs.fieldName (for example. getSObjects Schema. see Dynamic DML. This method is primarily used with describe information. For more information.SObjectType Returns the token for this sObject. see Dynamic SOQL. such as child relationships.Reference Apex sObject Methods Name getSObject Arguments String fieldName Return Type sObject Description Returns the value for the field specified by fieldName.fieldName (for example. getSObject Schema. put Schema. Schema. Schema. see Dynamic DML. For more information. For more information.MyObj. see Dynamic DML. see Dynamic SOQL. SObjectType.getDescribe(). fieldSets should always be followed by either a field set name or the getMap method. Instead.FieldSet> FsMap = 349 .Name.sObjectType.DMLOptions DMLOptions Void Sets the DMLOptions object for the sObject. Schema. The method returns the previous value of the field. Schema. see sObject Types on page 29.Reference Apex sObject Methods Name putSObject Arguments String fieldName sObject value Return Type sObject Description Sets the value for the field specified by fieldName. see Database DMLOptions Properties. Instead. This method is primarily used with dynamic DML for setting external IDs. The method returns the previous value of the field.sObjectType. Name fields Data Type Special Description Returns a special data type that should not be used by itself.DescribeFieldResult F = Schema.sObjectType fieldName sObject sObject value Sets the value for the field specified by the token Schema. For example. the DescribeSObjectResult object. sObject Describe Result Methods The following table describes the methods available for the sObject describe result. For more information. see Dynamic SOQL.DescribeSObjectResult d = Account. Schema. putSObject Schema.fields.Account. setOptions database. fields should always be followed by either a field member variable name or the getMap method. For more information. This method is primarily used with dynamic DML for setting external IDs. see Dynamic SOQL. For more information. see Understanding Apex Describe Information. For example. For more information. Map<String. For more information on sObjects. None of the methods take an argument. fieldSets Special Returns a special data type that should not be used by itself. This label is then used in the Salesforce user interface. For example. see Schema. The current user is not required to have access to a record type to see it in this list. The current user is not getLabelPlural String getLocalName String getName getRecordTypeInfos String List<Schema. However. Client applications that rely on these codes can use this way of determining object type to ensure forward compatibility.fieldSets. For object types that do not have a stable or predictable prefix. For example. the namespace portion of the name is omitted. getKeyPrefix getLabel String Returns the object's label.getMap().ChildRelationship> Returns a list of child relationships. Returns the object's plural label. String Returns the three-character prefix code for the object.Reference Apex sObject Methods Name Data Type Description d. which may or may not match the object name. Schema. the Account object includes Contacts and Opportunities as child relationships. Record IDs are prefixed with three-character codes that specify the type of the object (for example. an organization in the medical industry might change the label for Account to Patient. similar to the getName method. See the Salesforce online help for more information. which may or may not match the object name.RecordTypeInfo> getRecordTypeInfosByID Map<ID. Returns the name of the object Returns a list of the record types supported by this object. this field is blank. See the Salesforce online help for more information. getChildRelationships List<Schema. accounts have a prefix of 001 and opportunities have a prefix of 006).FieldSet Methods. Returns a map that matches record IDs to their associated record types. This label is then used in the Salesforce user interface. an organization in the medical industry might change the plural label for Account to Patients. Returns the name of the object.RecordTypeInfo> 350 . For more information. The DescribeSobjectResult object returns a value for objects that have a stable prefix. For example. which are the names of the sObjects that have a foreign key to the sObject being described. if the object is part of the current namespace. SObjectType object for the sObject. false otherwise. false otherwise Returns true if the object can be searched by the current user.com API version 19. Schema. contacts. true is returned for leads. Returns the Schema. false otherwise. see Schema. false otherwise. Returns true if the current user can see this field. Returns true if Chatter feeds are enabled for the object. false otherwise.SObjectType.RecordTypeInfo> Returns a map that matches record labels to their associated record type. Returns true if the object can be queried by the current user. Returns true if the object can be updated by the current user.SObjectType isAccessible Boolean Boolean Boolean Boolean Boolean Boolean Boolean isCreateable isCustom isCustomSetting isDeletable isDeprecatedAndHidden isFeedEnabled isMergeable Boolean isQueryable Boolean Boolean Boolean Boolean isSearchable isUndeletable isUpdateable 351 . and accounts. You can use this to create a similar sObject. false if it is a standard object. This method is only available for Apex classes and triggers saved using Salesforce. getSobjectType Schema. Returns true if the object is a custom object. Returns true if the object is a custom setting. false otherwise.0 and later. false otherwise. For more information. The current user is not required to have access to a record type to see it in this map. Returns true if the object can be merged with other objects of its type by the current user. Returns true if the object cannot be undeleted by the current user. Returns true if the object can be created by the current user. Reserved for future use. getRecordTypeInfosByName Map<String. false otherwise. false otherwise.Reference Apex sObject Methods Name Data Type Description required to have access to a record type to see it in this map. Returns true if the object can be deleted by the current user. false otherwise. getDescribe().getChildRelationships(). respectively. Map<Id.Account.Reference Apex sObject Methods ChildRelationship Methods If an sObject is a parent object.get(rt. Name getChildSObject getField getRelationshipName isCascadeDelete Data Type Schema. The following example assumes at least one record type has been created for the Account object: RecordType rt = [SELECT Id. For more information about governor limits. List<Schema. For example: Schema.Schema. Returns the name of the relationship. Returns true if the parent object can't be deleted because it is referenced by a child object. see Understanding Execution Governors and Limits on page 214. In addition to the getRecordTypeInfos method. The following table describes the methods available as part of the ChildRelationship object. false otherwise. Schema. false otherwise.RecordTypeInfo rtById = rtMapById. These methods return maps that associate RecordTypeInfo with record IDs and record labels. You can only use 100 getChildRelationships method calls per Apex request. You can only return 100 RecordTypeInfo objects per Apex request. A ChildRelationship object is returned from the sObject describe result using the getChildRelationship method.SObjectField String Boolean Boolean Boolean Description Returns the token of the child sObject on which there is a foreign key back to the parent sObject. Schema.SObjectType Schema.DescribeSObjectResult R = Account. List<Schema.getDescribe().id).getRecordTypeInfosById(). For example: Schema.RecordTypeInfo> RT = R. you can access the child relationship as well as the child sObject using the ChildRelationship object methods.getRecordTypeInfos().RecordTypeInfo> rtMapById = d. A RecordTypeInfo object is returned from the sObject describe result using the getRecordTypeInfos method. you can access information about the record type using the RecordTypeInfo object methods.SObjectType.DescribeSObjectResult R = Account. see Understanding Execution Governors and Limits on page 214. For more information about governor limits. Returns true if the child object is deleted when the parent object is deleted. 352 .Name FROM RecordType WHERE SobjectType='Account' LIMIT 1]. you can use the getRecordTypeInfosById and the getRecordTypeInfosByName methods. isDeprecatedAndHidden isRestrictedDelete RecordTypeInfo Methods If an sObject has a record type associated with it.SObjectType.SObjectType. Reserved for future use.DescribeSObjectResult d = Schema. Returns the token of the field that has a foreign key back to the parent sObject. None of the methods take an argument.ChildRelationship> C = R. The following table describes the methods available as part of the RecordTypeInfo object.rtByName).getDescribe(). getCalculatedFormula getController getDefaultValue getDefaultValueFormula getDigits getInlineHelpText getLabel String 353 . Returns true if this is the default record type mapping. None of the methods take an argument.Reference Apex sObject Methods Map<String. None of the methods take an argument. false otherwise. Returns the ID of this record type. returns the maximum size of the field. Name getByteLength Data Type Integer String Schema.AccountNumber. Returns the text label that is displayed next to the field in the Salesforce user interface. For more information. Name getName getRecordTypeId isAvailable Data Type String ID Boolean Description Returns the name of this record type. This method is only valid with Integer fields Returns the content of the field-level help. Use this method to display a list of available record types to the user when he or she is creating a new record.getRecordTypeInfosByName().Schema. Schema.RecordTypeInfo> rtMapByName = d.get(rt. see “Defining Field-Level Help” in the Salesforce online help. false otherwise. This label can be localized. System.name). Returns true if this record type is available to the current user. isDefaultRecordTypeMapping Boolean Describe Field Result Methods The following table describes the methods available as part of the field describe result. in bytes Returns the formula specified for this field Returns the token of the controlling field Returns the default value for this field Returns the default value specified for this field if a formula is not used Returns the maximum number of digits specified for the field.RecordTypeInfo rtByName = rtMapByName.sObjectField Object String Integer String Description For variable-length fields (including binary fields).DescribeFieldResult F = Account.assertEquals(rtById. The following is an example of how to instantiate a field describe result object: Schema. DisplayType isAccessible Boolean 354 . Returns the field name used in Apex Returns a list of PicklistEntry objects. see Schema. similar to the getName method. For more information about relationships and relationship names. 0 otherwise. Returns one of the SoapType enum values. depending on the type of field. This method returns a fault response if the number has too many digits to the left of the decimal point. Returns the token for this field Returns one of the DisplayType enum values. Returns true if the current user can see this field.sObjectType objects for the parent objects of this field. see Understanding Relationship Names in the Force.SOAPType getSObjectField getType Schema. false otherwise getLocalName getName getPicklistValues String List <Schema. returns the maximum size of the field in Unicode characters (not bytes) Returns the name of the field.PicklistEntry> Integer getPrecision getReferenceTo List <Schema. otherwise there is only one. However.Reference Apex sObject Methods Name getLength Data Type Integer String Description For string fields. If the isNamePointing method returns true. Any extra digits to the right of the decimal point are truncated. returns the maximum number of digits that can be stored.SOAPType Enum Values on page 361. including all numbers to the left and to the right of the decimal point (but excluding the decimal point character) Returns a list of Schema. depending on the type of field. if the field is part of the current namespace. there is more than one entry in the list. For more information about relationships and relationship names. For fields of type Double. For more information.sObjectField Schema.sObjectType> getRelationshipName String getRelationshipOrder Integer getScale Integer getSOAPType Schema. For more information. see Understanding Relationship Names in the Force.com SOQL and SOSL Reference. A runtime error is returned if the field is not a picklist.DisplayType Enum Values on page 357. see Schema. the namespace portion of the name is omitted.com SOQL and SOSL Reference. Returns 1 if the field is a child. returns the number of digits to the right of the decimal point. Returns the name of the relationship. For fields of type Double. false otherwise. in the Opportunity object. non-createable text fields with a maximum length of 30 characters. Returns true if the field is case sensitive. Returns true if the child object is deleted when the parent object is deleted. false otherwise.Reference Apex sObject Methods Name isAutoNumber Data Type Boolean Description Returns true if the field is an Auto Number field. false otherwise Returns true if the field can be created by the current user. For example. false otherwise Returns true if the field can be included in the GROUP BY clause of a SOQL query. false otherwise Reserved for future use. false otherwise Returns true if the field is a custom field. the Probability field has this attribute because its value is derived from the Stage field. false otherwise. Analogous to a SQL IDENTITY type. If true. false otherwise. Auto Number fields are configured entirely in the Salesforce user interface. Note that custom formula fields are always read-only. This method is only available for Apex isCascadeDelete Boolean Boolean Boolean Boolean Boolean isCaseSensitive isCreateable isCustom isDefaultedOnCreate isDependentPicklist Boolean Boolean Boolean Boolean Boolean isDeprecatedAndHidden isExternalID isFilterable isGroupable 355 . Auto Number fields are read-only. Similarly. the Owner has this attribute on most objects because its value is derived from the current user (if the Owner field is not specified). false otherwise Returns true if the field can be used as part of the filter criteria of a WHERE statement. even if a value for this field is not passed in on the create call. false if it is a standard object Returns true if the field receives a default value when created. isCalculated Boolean Returns true if the field is a custom formula field. false otherwise. Returns true if the picklist is a dependent picklist. Returns true if the field is used as an external ID. Auto Number fields are used to provide a unique ID that is independent of the internal object ID (such as a purchase order number or invoice number). Salesforce implicitly assigns a value for this field when the object is created. false otherwise. If a compound name is present. Another example is a custom formula field that has an IMAGE text function. false otherwise. false otherwise. false otherwise isNillable Boolean isPermissionable Boolean Boolean isRestrictedDelete isRestrictedPicklist Boolean Boolean isSortable 356 . isHtmlFormatted Boolean Returns true if the field has been formatted for HTML and should be encoded for display in HTML. A non-nillable field must have a value for the object to be created or saved. Returns true if the field is a restricted picklist. false otherwise Returns true if a query can sort on the field. false otherwise. false otherwise Returns true if the field is a name field. Returns true if field permissions can be specified for the field. This method is used to identify the name field for standard objects (such as AccountName for an Account object) and custom objects. Returns true if the field is nillable. isIdLookup Boolean Boolean isNameField isNamePointing Boolean Returns true if the field can have multiple types of objects as parents. the Name field on a person account. a task can have both the Contact/Lead ID (WhoId) field and the Opportunity/Account ID (WhatId) field return true for this method. false otherwise. One example of a field that returns true for this method is a hyperlink custom formula field. Returns true if the field can be used to specify a record in an upsert method. because either of those objects can be the parent of a particular task record. except where the FirstName and LastName fields are used instead (such as on the Contact object). This method returns false otherwise. Returns true if the parent object can't be deleted because it is referenced by a child object.0 and higher. A nillable field can have empty content. for example. For example. isNameField is set to true for that record. Objects can only have one name field.Reference Apex sObject Methods Name Data Type Description classes and triggers saved using API version 18. URL. Boolean. Double. Integer. see Enum Methods on page 339. Type Field Value anytype What the Field Object Contains Any value of the following types: String. For more information about the methods shared by all enums. Date. or Email. false otherwise Returns true if: • The field can be edited by the current user. DateTime.DisplayType Enum Values A Schema. Picklist. see Field Types in the Object Reference for Salesforce and Force. which provide a set of enumerated values from which multiple values can be selected Percent values 357 .DisplayType enum value is returned by the field describe result's getType method. Percent. ID. Date DateTime Double Email EncryptedString ID Integer MultiPicklist Percent Date values DateTime values Double values Email addresses Encrypted string Primary key field for an object Integer values Multi-select picklists. For more information. Base64-encoded arbitrary binary data (of type base64Binary) Boolean (true or false) values Comboboxes.com.Reference Apex sObject Methods Name isUnique Data Type Boolean Boolean Description Returns true if the value for the field must be unique. or • Child records in a master-detail relationship field on a custom object can be reparented to different parent records false otherwise isUpdateable isWriteRequiresMasterRead Boolean Returns true if writing to the detail object requires read sharing instead of read/write sharing of the parent. Schema. which provide a set of enumerated values and allow the user to specify a value not in the list Currency values base64 Boolean Combobox Currency DataCategoryGroupReference Reference to a data category group or a category unique name. getDescribe().PicklistEntry object is returned from the field describe result using the getPicklistValues method.getDescribe(). None of the methods take an argument.sObjectField object is returned from the field describe result using the getControler and getSObjectField methods. Only one item in a picklist can be designated as the default. For example: Schema. One of the items can be configured as the default item. which provide a set of enumerated values from which only one value can be selected Cross-references to a different object.sObjectField T = F.DescribeFieldResult F = Account.DescribeFieldResult Returns the describe field result for this field. For example: Schema.PicklistEntry> P = F. Schema. 358 . The following table describes the method available as part of the sObjectField object.PicklistEntry Methods Picklist fields contain a list of one or more items from which a user chooses a single item. A Schema.DescribeFieldResult F = Account. Single-select picklists. They display as drop-down lists in the Salesforce user interface.Industry. This method does not take an argument. Name getDescribe Data Type Description Schema. You can only use 100 getPicklistValue method calls per Apex request. isDefaultValue Schema. List<Schema. Name getLabel getValue isActive Data Type String String Boolean Boolean Description Returns the display name of this item in the picklist Returns the value of this item in the picklist Returns true if this item must be displayed in the drop-down list for the picklist field in the user interface. false otherwise Returns true if this item is the default value for the picklist.getPicklistValues(). For more information about governor limits.getSObjectField(). analogous to a foreign key field String values String values that are displayed as multiline text fields Time values URL values that are displayed as hyperlinks Schema. Values can include alphabetic characters. Client applications are responsible for phone number formatting.Industry.sObjectField A Schema. The following table describes the methods available as part of the PicklistEntry object. see Understanding Execution Governors and Limits on page 214.Reference Apex sObject Methods Type Field Value Phone Picklist Reference String TextArea Time URL What the Field Object Contains Phone numbers. false otherwise. pass the ID of an existing record in the database. After you create a new sObject. or from the sObject describe result using the getSObjectType method. sObject Constructs a new sObject of this type.sObjectType A Schema. 359 .Reference Apex sObject Methods Schema. Otherwise.getReferenceTo(). of the specified record type ID and with default custom field values. List<Schema.sObjectType> P = F. If no record type exists for this sObject.getDescribe(). The loadDefaults argument specifies whether to populate custom fields with their predefined default values (true) or not (false).Industry. For example: Schema. the sObject returned has all fields set to null. The following table describes the methods available as part of the sObjectType object. the default record type is used. Only the fields you set new values for are updated and all other fields which are not system fields are preserved.DescribeSObjectResult Returns the describe sObject result for this field. You can set any updateable field to desired values and then update the record in the database.sObjectType object is returned from the field describe result using the getReferenceTo method. The recordTypeId argument specifies the record type ID of the sObject to create. Name getDescribe newSObject Argument Data Type Description Schema. make sure to provide a value before inserting the new sObject. see Creating sObjects Dynamically. If the sObject has record types and you specify null. For the argument. with the specified ID. newSObject ID Id sObject Constructs a new sObject of this type. and optionally. Remarks: • For required fields that have no default values. newSObject ID recordTypeId sObject Boolean loadDefaults Constructs a new sObject of this type. the insertion results in an error. use null. For an example. An example is the Account Name field or a master-detail relationship field.DescribeFieldResult F = Account. see “About Default Field Values” in the Salesforce online help.Name = 'Acme2'.Reference Apex sObject Methods Name Argument Data Type Description • Since picklists and multi-select picklists can have default values specified per record type.sObjectType.Name = 'Acme'. using the newSObject method. true). which is a required field that doesn’t have a default value.Id. Sample: Create New sObject with Default Values This sample creates an account with any default values populated for its custom fields.sObjectType. // Insert new account insert acct2. This method populates read-only custom fields of the new sObject with default values. // This is for record type RT1 of Account ID rtId = [SELECT Id FROM RecordType WHERE sObjectType='Account' AND Name='RT1']. 360 . inserting more than one new sObject will cause a run-time exception because of duplicate field values. even though these fields cannot be edited after they’re inserted. You can then insert the new sObject with the read-only fields. Account acct2 = (Account)Account. // Provide a value for Name acct2. It also creates a second account for a specific record type. If the loadDefaults argument is false. see Sample: Create New sObject with Default Values. // Insert new account insert acct. For both accounts. • • • • To learn more about default field values. If a custom field is marked as unique and also provides a default value. For an example. if any.newSObject(rtId.newSObject(null. If fields have no predefined default values and the loadDefaults argument is true. // Create an account with predefined default values Account acct = (Account)Account. this method populates the default value corresponding to the record type specified. before inserting the new accounts. the sample sets the Name field. true). // Provide a value for Name acct. this method creates the sObject with field values of null. this method creates the sObject with field values of null. 361 .SOAPType Enum Values A schema.FieldSet Methods Contains methods for discovering and retrieving the details of field sets created on sObjects. For more information about the methods shared by all enums. Boolean. Map<String. Base64-encoded arbitrary binary data (of type base64Binary) Boolean (true or false) values Date values DateTime values Double values Primary key field for an object Integer values String values Time values base64binary Boolean Date DateTime Double ID Integer String Time Schema. The following lines of code are equivalent to the prior sample: Schema. see SOAPTypes in the SOAP API Developer's Guide. Integer. Schema. The key of the returned Map is the field set name. Usage Use the methods in the Schema.DescribeSObjectResult d = Account. Double. and so on. Date or DateTime. Field sets are also available from sObject describe results. and get details about the field set itself. Map<String.SObjectType.fieldSets. such as the name.Reference Apex sObject Methods Schema. namespace. label.SOAPType enum value is returned by the field describe result getSoapType method.FieldSet> FsMap = Schema.getDescribe(). ID.Account. Note: This release contains a beta version of field sets that is production-quality but has known limitations.getMap(). Type Field Value anytype What the Field Object Contains Any value of the following types: String. The following example shows how to get a collection of field set describe result objects for an sObject.sObjectType. Schema.FieldSet class to discover the fields contained within a field set.FieldSet> FsMap = d.fieldSets. For more information. see Enum Methods on page 339. and the value is the corresponding field set describe result.getMap(). it’s the namespace of your organization. None of the methods take an argument. when you know the name of the field set in advance.getMap(). and so on. It’s often intended for administrators who might be configuring a field set defined in a managed package. a dynamic SOQL-ready field path. rather than for end users. The following two lines of code retrieve the same field set: Schema.FieldSet fs2 = Schema. type. The following example shows how to get a collection of field set member describe result objects for a specific field set on an sObject: List<Schema. getFields List<FieldSetMember> Returns a list of Schema.FieldSetMember Methods Contains methods for accessing the metadata for field set member fields. Methods The following are instance methods of the Schema. Returns the field set’s name.get('field_set_name').getFields(). and the field set is defined in your organization.SObjectType. such as the field label. Description is a required field for a field set.fieldSets. Returns the field set’s namespace. Schema. Schema.fieldSets.FieldSetMember objects for the fields making up the field set.SObjectType. Usage Use the methods in the Schema.Account.field_set_name.field_set_name.FieldSet class.Account. 362 . If you know the name of the field set in advance.Reference Apex sObject Methods To work with an individual field set. Otherwise. you can access its fields more directly using an explicit reference to the field set: List<Schema.SObjectType. getSObjectType SObjectType Returns the Schema.getMap(). getLabel getName getNamespace String String String Returns the text label that is displayed next to the field in the Salesforce user interface.sObjectType of the sObject containing the field set definition.FieldSet fs1 = Schema.Account. you can access it via the map of field sets on an sObject or.getFields().fieldSets. The returned namespace is an empty string if your organization hasn’t set a namespace.FieldSetMember> fields = Schema.SObjectType.FieldSetMember class to get details about fields contained within a field set.get('field_set_name').FieldSetMember> fields = Schema. using an explicit reference to the field set.fieldSets. intended to describe the context and content of the field set.Account. or the namespace of the managed package containing the field set. Method getDescription Return Type String Description Returns the field set’s description. Sample: Displaying a Field Set on a Visualforce Page This sample uses Schema. } query += 'Id. Schema. for(Schema. return Database.Reference Apex sObject Methods Methods The following are instance methods of the Schema. } } The Visualforce page using the above controller is simple: <apex:page controller="MerchandiseDetails"> <apex:form > <apex:pageBlock title="Product Details"> <apex:pageBlockSection title="Product"> <apex:inputField value="{!merch.merch = getMerchandise().FieldSetMember f : this. } private Merchandise__c getMerchandise() { String query = 'SELECT '. '.query(query). The Visualforce page uses the MerchandiseDetails class as its controller.FieldSets.getFieldPath() + '.getFields()) { query += f.FieldSetMember> getFields() { return SObjectType.Merchandise__c. public class MerchandiseDetails { public Merchandise__c merch { get.DisplayType Returns the field’s Apex data type.getFields().Name}"/> </apex:pageBlockSection> <apex:pageBlockSection title="Dimensions"> 363 . otherwise. The list of fields is then used to construct a SOQL query that ensures those fields are available for display. set.FieldSetMember class.FieldSetMember methods to dynamically get all the fields in the Dimensions field set for the Merchandise custom object. } public List<Schema. Name FROM Merchandise__c LIMIT 1'. } public MerchandiseDetails() { this. otherwise. false.FieldSet and Schema. Returns true if the field is required by the field set. None of the methods take an argument. See Displaying a Field Set on a Visualforce Page for an example of how to use this method.Dimensions. Returns a field path string in a format ready to be used in a dynamic SOQL query. Method getDBRequired Return Type Boolean Description Returns true if the field is required by the field’s definition in its sObject. getFieldPath String getLabel getRequired getType String Boolean Returns the text label that’s displayed next to the field in the Salesforce user interface. false. 0 or earlier. Description Returns a map of the data sets defined for the custom setting. The methods are divided into those that work with list custom settings. If no data is defined for the specified data set. The following are the instance methods for list custom settings. and those that work with hierarchy custom settings.com API version 20. A field in a field set can be required by either the field set definition. are converted to lower case. that is. f. If no data is defined for the specified data set.0 and later. If no data set is defined. There are two types of custom settings: hierarchy and list. which are the keys in the returned map. Custom Settings Methods Custom settings methods are all instance methods. 364 . or the field’s own definition. this method returns null. CustomSetting__c> getInstance String dataset_name CustomSetting__c Returns the custom setting data set record for the specified dataset_name.dbrequired)}"/> </apex:repeat> </apex:pageBlockSection> </apex:pageBlock> </apex:form> </apex:page> One thing to note about the above markup is the expression used to determine if a field on the form should be indicated as being a required field. the case of the data set names in the returned map keys is not changed and the original case is preserved. This method returns the exact same object as getValues(dataset_name).fieldPath]}" required="{!OR(f. Note: For Apex saved using Salesforce.Reference Apex sObject Methods <apex:repeat value="{!fields}" var="f"> <apex:inputField value="{!merch[f.com API version 21. For Apex saved using Salesforce. getValues String dataset_name CustomSetting__c Returns the custom setting data set record for the specified dataset_name. they are called by and operate on a particular instance of a custom setting. the data set names. this method returns an empty map. Table 1: List Custom Settings Methods Name getAll Arguments Return Type Map<String Data_set_name. This method returns the exact same object as getInstance(dataset_name). this method returns null. The expression handles both cases.required. the returned custom setting has empty fields.” for the profile “System Administrator. Also. this method returns null. this method returns the custom setting data set record with fields merged from field values defined at the lowest hierarchy level. The fields returned in the custom setting record are merged based on the lowest level fields that are defined in the hierarchy. Note: For Apex saved using Salesforce. this method returns a new custom setting object. if no custom setting data is defined in the hierarchy.” who also shares the “System Administrator” profile. If no custom setting data is defined for the user.Reference Apex sObject Methods The following are the instance methods for hierarchy custom settings: Table 2: Hierarchy Custom Settings Methods Name getInstance Arguments Return Type CustomSetting__c Description Returns a custom setting data set record for the current user. You can add this new custom setting record for the user by using insert or upsert. starting with the user. except for the SetupOwnerId field which contains the user ID. Merged fields: If you have a custom setting data set with fields A and B for the user “Uriel Jones” and for the profile “System Administrator.” and for the organization as a whole.” and field A is defined for Uriel Jones.0 or earlier. field B is null but is defined for the System Adminitrator profile. but no data is defined for Barbara as a user. Examples: • Custom setting data set defined for the user: If you have a custom setting data set defined for the user “Uriel Jones. this method returns the custom setting record for Uriel Jones with field A for Uriel Jones and field B from the System Administrator profile. No custom setting data set record defined for the user: If the current user is “Barbara Mahonie. this method returns the custom setting record defined for Uriel Jones. and the user running the code is Uriel Jones. this method returns a new custom setting record with the ID set • • 365 . The new custom setting object contains an ID set to null and merged fields from higher in the hierarchy.com API version 21. If no custom setting data is defined in the hierarchy. You can add this new custom setting record for the user by using insert or upsert. The lowest level custom setting record and fields are returned. You can add this new custom setting for the profile by using insert or upsert.0 or earlier. The new custom setting object contains an ID set to null and merged fields from higher in the hierarchy. Note: For Apex saved using Salesforce. if no custom setting data is defined in the hierarchy. getInstance ID Profile_Id CustomSetting__c Returns the custom setting data set record for the specified Profile_Id. the returned custom setting has empty fields. The lowest level custom setting record and fields are returned. The new custom setting object contains an ID set to null and with merged fields from your organization's default values. the returned custom setting has empty fields. If no custom setting data is defined in the hierarchy. this method returns the custom setting data set record with fields merged from field values defined at the lowest hierarchy level. If no custom setting data is defined in the hierarchy. If no custom setting data is defined for the user. this method returns a new custom setting object.com API version 21. Use this when you want to explicitly retrieve data for the custom setting at the profile level. This method is equivalent to a method call to getInstance(User_Id) for the current user.Reference Apex sObject Methods Name Arguments Return Type Description to null and with fields merged based on the fields defined in the lowest level in the hierarchy. getInstance ID User_Id CustomSetting__c Returns the custom setting data set record for the specified User_Id.0 or earlier. this method returns the custom setting data set record with fields 366 . Also. If no custom setting data is defined for the profile. except for the SetupOwnerId field which contains the profile ID. Use this when you want to explicitly retrieve data for the custom setting at the user level. except for the SetupOwnerId field which contains the user ID. starting with the user.com API version 21. this method returns null. this method returns a new custom setting record. Note: For Apex saved using Salesforce. However.values(). see “Custom Settings Overview” in the Salesforce online help. To benefit from caching.com API version 21. Returns the custom setting data set for the specified Profile_Id.0 or earlier. getValues ID Profile_Id CustomSetting__c For more information on custom settings. which enables efficient access without the cost of repeated queries to the database. Use this if you only want the subset of custom setting data that has been defined at the profile level.Reference Apex sObject Methods Name Arguments Return Type Description merged from field values defined at the lowest hierarchy level. querying custom settings data using Standard Object Query Language (SOQL) doesn't make use of the application cache and is similar to querying a custom object. For example. This example determines if the value of the first data set is equal to the string PC. Also. but has no value assigned at the user or profile level. Note: All custom settings data is exposed in the application cache. use other methods for accessing custom settings data such as the Apex Custom Settings methods. but has no value assigned at the user or profile level. this method returns null. 367 . For example. Note: For Apex saved using Salesforce. this method returns null if no custom setting data is defined for the organization. suppose you have a custom setting field that has been assigned a value of "foo" at the organizational level. Use this if you only want the subset of custom setting data that has been defined at the user level. this method returns an empty custom setting object. Custom Setting Examples The following example uses a list custom setting called Games. List<Games__C> mcs = Games__c. Games has a field called GameType. Using getValues(User_Id) returns null for this custom setting field. getValues ID User_Id CustomSetting__c Returns the custom setting data set record for the specified User_Id. getOrgDefaults CustomSetting__c Returns the custom setting data set record for the organization. boolean textField = null.getall(). if no custom setting data is defined in the hierarchy. Using getValues(Profile_Id) returns null for this custom setting field. starting with the profile. If no custom setting data is defined for the organization. suppose you have a custom setting field that has been assigned a value of "foo" at the organizational level. System. User settings OverrideMe: Fluffy DontOverrideMe is not set. The following example shows how to use hierarchy custom settings methods. the example demonstrates how getValues returns fields in the custom setting record only for the specific user or profile. a user named Robert has a System Administrator profile. Hierarchy Custom Setting Examples In the following example.Corporate_number__c.getValues('United States').assertEquals(myCCinst. Foundation_Countries__c myCS1 = Foundation_Countries__c. and user settings for this example are as follows: Organization settings OverrideMe: Hello DontOverrideMe: World Profile settings OverrideMe: Goodbye DontOverrideMe is not set. In addition. This example uses a hierarchy custom setting called Hierarchy.OverrideMe__c == 'Fluffy'). String myCCInst = myCS2.Assert(CS. The code returns the value for the profile specified with pid. and doesn't merge values from other levels of the hierarchy.Reference Apex sObject Methods if (mcs[0]. profile. For getInstance.assert(CS. The following example uses a custom setting from Country and State Code Custom Settings Example.DontOverrideMe__c == 'World'). the example shows how field values that aren't set for a specific user or profile are returned from fields defined at the next lowest level in the hierarchy. 368 . The example also shows how to use getOrgDefaults. The following example demonstrates the result of the getInstance method if Robert calls it in his organization: Hierarchy__c CS = Hierarchy__c. Finally. Hierarchy has two fields: OverrideMe and DontOverrideMe. the hierarchy custom setting GamesSupport has a field called Corporate_number. System. String myCCVal = myCS1.Country_code__c. The organization.getInstance('United States').getInstance(). string mPhone = mhc.GameType__c == 'PC') { textField = true. getValues returns null for any fields that aren't set. } system. GamesSupport__c mhc = GamesSupport__c.Country_code__c.getInstance(pid). This example demonstrates that the getValues and getInstance methods list custom setting return identical values. true).assertEquals(textField. Instead. Foundation_Countries__c myCS2 = Foundation_Countries__c. The example is identical if you choose to use the getValues method. system. myCCVal). the result is: Hierarchy__c CS = Hierarchy__c.OverrideMe__c == 'Hello'). the result is different. System.DontOverrideMe__c == 'World').OverrideMe__c == 'Fluffy'). System. System. System. For example. Country and State Code Custom Settings Example This example illustrates using two custom setting objects for storing related information. the result is: Hierarchy__c CS = Hierarchy__c.DontOverrideMe__c == 'World'). In the following example.Reference Apex sObject Methods If Robert passes his user ID specified by RobertId to getInstance.Assert(CS. System. // Note how this value is null.assert(CS.getValues(RobertId).assert(CS. because you are returning // data specific for the profile System. The Foundation_Countries custom setting is a list type custom setting and has a single field. When Robert tries to return the data set for the organization using getOrgDefaults.getInstance(RobertId). the results are the same.OverrideMe__c == 'Goodbye'). If Robert passes the System Administrator profile ID specified by SysAdminID to getInstance.assert(CS.getValues(SysAdminID).assert(CS.DontOverrideMe__c == null). // Note how this value is null. the result is: Hierarchy__c CS = Hierarchy__c. System. and a Visualforce page to display the data in a set of related picklists. because you are returning // data specific for the user System. System.OverrideMe__c == 'Goodbye'). By using the getValues method. Country_Code.Assert(CS.DontOverrideMe__c == null). 369 . This is because the lowest level of data in the custom setting is specified at the user level.Assert(CS. if Robert passes his user ID RobertId to getValues.DontOverrideMe__c == 'World'). country and state codes are stored in two different custom settings: Foundation_Countries and Foundation_States. If Robert passes his System Administrator profile ID SysAdminID to getValues.OverrideMe__c == 'Fluffy').getOrgDefaults(). System.getInstance(SysAdminID).assert(CS. Robert can get the hierarchy custom setting values specific to his user and profile settings.Assert(CS.Assert(CS. The data specified for the profile is returned: Hierarchy__c CS = Hierarchy__c. Hierarchy__c CS = Hierarchy__c. 370 .Reference Apex sObject Methods The Foundation_States custom setting is also a List type of custom setting and has the following fields: • • • Country Code State Code State Name The Visualforce page shows two picklists: one for country and one for state. set. } public String country {get. options. 371 .Reference Apex sObject Methods <apex:page controller="CountryStatePicker"> <apex:form > <apex:actionFunction name="rerenderStates" rerender="statesSelectList" > <apex:param name="firstParam" assignTo="{!country}" value="" /> </apex:actionFunction> <table><tbody> <tr> <th>Country</th> <td> <apex:selectList id="country" styleclass="std" size="1" value="{!country}" onChange="rerenderStates(this. '-.value)"> <apex:selectOptions value="{!countriesSelectList}"/> </apex:selectList> </td> </tr> <tr id="state_input"> <th>State/Province</th> <td> <apex:selectList id="statesSelectList" styleclass="std" size="1" value="{!state}"> <apex:selectOptions value="{!statesSelectList}"/> </apex:selectList> </td> </tr> </tbody></table> </apex:form> </apex:page> The Apex controller CountryStatePicker finds the values entered into the custom settings. then returns them to the Visualforce page.add(new SelectOption(''.} // Generates country dropdown from country settings public List<SelectOption> getCountriesSelectList() { List<SelectOption> options = new List<SelectOption>().Select One --')). public with sharing class CountryStatePicker { // Variables to store country and state selected by user public String state { get. set. add(new SelectOption(state.addAll(states. // Filter states that belong to the selected country Map<String. country. } } Apex System Methods The following are Apex system classes.keySet()). options.Name)).country) { states.size() > 0) { options. just say not required in the dropdown. • • • ApexPages Approval Database ◊ Database Batch 372 .get(stateName). countryNames.getAll(). stateNames. // Create the Select Options. 'Not Required')).country_code__c.state_name__c)).sort().put(state. state. state).values()) { if (state. Foundation_States__c>(). Foundation_Countries__c> countries = Foundation_Countries__c.add(new SelectOption(country.get(countryName). if (options. '-. // Find all the states we have in custom settings.country_code__c == this. // Generate the Select Options based on the final sorted list for (String stateName : stateNames) { Foundation_States__c state = states. options.state_code__c. countryNames. } return options.keySet()). // Sort them by name List<String> countryNames = new List<String>(). } // If no states are found. Foundation_States__c> states = new Map<String.add(new SelectOption(''. } else { options. } return options. stateNames. for(Foundation_States__c state : allstates. Map<String. public List<SelectOption> getStatesSelectList() { List<SelectOption> options = new List<SelectOption>().name.add(0.getAll(). } } // Sort the states based on their names List<String> stateNames = new List<String>(). } // To generate the states picklist based on the country selected by user. new SelectOption(''.sort().addAll(countries.Reference Apex System Methods // Find all the countries in the custom setting Map<String. for (String countryName : countryNames) { Foundation_Countries__c country = countries.Select One --')). Foundation_States__c> allstates = Foundation_States__c. In addition. Boolean Returns true if there are messages associated with the current context. The following table lists the ApexPages methods: Name addMessage Arguments sObject ApexPages. hasMessages 373 . Adds a list of messages to the current page context based on a thrown exception. as well as to reference the current page.Message Return Type Void Void Description Add a message to the current page context.Message[] Returns a list of the messages associated with the current context. false otherwise. ApexPages is used as a namespace for the PageReference and Message classes. addMessages Exception ex getMessages ApexPages.Reference Apex System Methods ◊ Database DMLOptions ◊ Database EmptyRecycleBinResult ◊ Database Error • JSON Support ◊ JSON Methods ◊ JSONGenerator Methods ◊ JSONParser Methods • • • • Limits Math MultiStaticResourceCalloutMock Apex REST ◊ RestContext Methods ◊ RestRequest Methods ◊ RestResponse Methods • • • • • • • • • Search StaticResourceCalloutMock System Test TimeZone Type URL UserInfo Version ApexPages Methods Use ApexPages to add and check for messages associated with the current page. insert a.ProcessRequest Approval.ProcessSubmitRequest req1 = new Approval.ProcessSubmitRequest(). process Approval. // Submit the approval request for the account Approval. and approves or [] [] rejects existing approval requests. Approval Methods The following table lists the static Approval methods.ProcessResult Submits a new approval request and approves or rejects ProcessRequest existing approval requests. Boolean opt_allOrNone The optional opt_allOrNone parameter specifies whether the operation allows for partial success.ProcessRequest Approval. Approval is also used as a namespace for the ProcessRequest and ProcessResult classes.0).Severity Return Type Boolean Description Returns true if messages of the specified severity exist. req1. Name process Arguments Return Type Description Approval. If you specify false for this parameter and an approval fails. For example: // Insert an account Account a = new Account(Name='Test'. the remainder of the approval processes can still succeed. process Approval.ProcessResult result = Approval.ProcessRequest Approval.Reference Apex System Methods Name hasMessages Arguments ApexPages. // Create an approval request for the account Approval. false otherwise.setObjectId(a.ProcessResult Submits a new approval request and approves or rejects ProcessRequests existing approval requests. ProcessRequests 374 .process(req1). annualRevenue=100.ProcessResult Submits a list of new approval requests.id). The optional opt_allOrNone parameter specifies whether the operation allows partial success. Each executed convertLead method counts against the governor limit for DML statements. Boolean opt_allOrNone convertLead LeadConvert[] leadsToConvert Boolean opt_allOrNone Database. the remainder of the approval processes can still succeed. which failed. For more information on Apex approval processing. For example.Reference Apex System Methods Name process Arguments Return Type Description Approval. String QueryString = 'SELECT count() FROM Account'.ProcessRequest Approval. 375 . ProcessRequests Boolean opt_allOrNone The optional opt_allOrNone parameter specifies whether the operation allows for partial success. which failed. the remainder of the DML operation can still succeed. Each executed convertLead method counts against the governor limit for DML statements. Database Methods The following are the system static methods for Database. and why. LeadConvert Result[] Converts a list of LeadConvert objects into accounts and contacts. as LeadConvertResult well as (optionally) an opportunity. and why. see Apex Approval Processing Classes on page 539. Name convertLead Arguments LeadConvert leadToConvert. Return Type Description Database. If you specify false for this parameter and an approval fails. and approves or [] [] rejects existing approval requests. This method returns a result object that can be used to verify which records succeeded. The optional opt_allOrNone parameter specifies whether the operation allows partial success. as well as (optionally) opportunties. countQuery String query Integer Returns the number of records that a dynamic SOQL query would return when executed. Cconverts a lead into an account and contact. This method returns a result object that can be used to verify which records succeeded.ProcessResult Submits a list of new approval requests. If you specify false for this parameter and a record fails. the remainder of the DML operation can still succeed. If you specify false for this parameter and a record fails. delete is analogous to the delete() statement in the SOAP API. which failed. Each executed delete method counts against the governor limit for DML statements. the remainder of the DML operation can still succeed. If you specify false for this parameter and a record fails. from your organization’s data. Each executed countQuery method counts against the governor limit for SOQL queries. delete SObject[] recordsToDelete DeleteResult[] Boolean opt_allOrNone Deletes a list of existing sObject records. which failed. delete is analogous to the delete() statement in the SOAP API. If you specify false for this parameter and a record fails. such as individual accounts or contacts. and why.Reference Apex System Methods Name Arguments Return Type Description Integer i = Database. delete RecordID ID Boolean opt_allOrNone DeleteResult Deletes existing sObject records. the remainder of the DML operation can still succeed. such as an individual account or contact. from your organization’s data. The optional opt_allOrNone parameter specifies whether the operation allows partial success. and why. from your organization's data.countQuery(QueryString). This method returns a result object that can be used to verify which records succeeded. Each executed delete method counts against the governor limit for DML statements. the remainder of the DML operation can still succeed. such as individual accounts or contacts. delete SObject recordToDelete Boolean opt_allOrNone DeleteResult Deletes an existing sObject record. The optional opt_allOrNone parameter specifies whether the operation allows partial success. This method returns a result object that can be used to verify which records succeeded. delete is analogous to the delete() statement in the SOAP API. For more information. see Dynamic SOQL on page 172. This method returns a result object that 376 . If you specify false for this parameter and a record fails. The optional opt_allOrNone parameter specifies whether the operation allows partial success. If the logged in user has “Modify All Data” permission. • Only 10. Each executed emptyRecycleBin method counts against the governor limit for DML statements. otherwise an error occurs. such as individual accounts or contacts. All related records are automatically removed.Reference Apex System Methods Name Arguments Return Type Description can be used to verify which records succeeded. which failed. Each executed delete method counts against the governor limit for DML statements. or the recycle bins of any subordinates. Only include the Id of the top level account. • The logged in user can delete any record that he or she can query in their Recycle Bin. he or she can query and delete records from any Recycle Bin in the organization. the remainder of the DML operation can still succeed. which failed. contracts. 377 . For example. The optional opt_allOrNone parameter specifies whether the operation allows partial success. and why. opportunities. Note the following: • After records are deleted using this method they cannot be undeleted. from your organization’s data. EmptyRecycleBin Result[] Permanently deletes the specified records from the recycle bin. and so on are also deleted. Each executed delete method counts against the governor limit for DML statements. • Deleted items are added to the number of items processed by a DML statement. emptyRecycleBin RecordIds []Ids Database. and the method call is added to the total number of DML statements issued. if an account record is deleted. all related contacts.000 records can be specified for deletion. This method returns a result object that can be used to verify which records succeeded. delete is analogous to the delete() statement in the SOAP API. If you specify false for this parameter and a record fails. and why. • Cascade delete record IDs should not be included in the list of IDs. delete RecordIDs []IDs Boolean opt_allOrNone DeleteResult[] Deletes a list of existing sObject records. Permanently deletes the specified sObjects from the recycle bin. For example. otherwise an error occurs.Reference Apex System Methods Name Arguments Return Type Database.000 sObjects can be specified for deletion. if an account is deleted. and the method call is added to the total number of DML statements issued. contracts. opportunities. he or she can query and delete sObjects from any Recycle Bin in the organization. If the logged in user has “Modify All Data” permission. • The logged in user can delete any sObject that he or she can query in their Recycle Bin. all related contacts. EmptyRecycleBin Result[] 378 . contracts. If the logged in user has “Modify All Data” permission. emptyRecycleBin sObject sObject emptyRecycleBin sObjects []listOfSObjects Database. or the recycle bins of any subordinates. and so on are also deleted. • Do not include an sObject that was deleted due to a cascade delete. • Only 10. • The logged in user can delete any sObject that he or she can query in their Recycle Bin. and so on are also deleted. if an account is deleted. All related sObjects are automatically removed. Only include sObjects of the top level account. or the recycle bins of any subordinates. Note the following: • After an sObject is deleted using this method it cannot be undeleted. opportunities. All related sObjects are automatically removed. For example. Only include sObjects of the top level account. • Do not include an sObject that was deleted due to a cascade delete. Each executed emptyRecycleBin method counts against the governor limit for DML statements. • Deleted items are added to the number of items processed by a DML statement. otherwise an error occurs. he or she can query and delete sObjects from any Recycle Bin in the organization. • Only 10.000 sObjects can be specified for deletion. EmptyRecycleBin Result Description Permanently deletes the specified sObject from the recycle bin. Note the following: • After an sObject is deleted using this method it cannot be undeleted. all related contacts. Understanding Apex Managed Sharing. Each executed getQueryLocator method counts against the governor limit of 10. and StandardSetController Class. and StandardSetController Class. see Using Batch Apex on page 177. For more information. see Using Batch Apex on page 177. see Database Batch Apex Objects and Methods. The value for scope must be greater than 0. You can't use getQueryLocator with any query that contains an aggregate function. Understanding Apex Managed Sharing. For more information. and the method call is added to the total number of DML statements issued.Reference Apex System Methods Name Arguments Return Type Description • Deleted items are added to the number of items processed by a DML statement. executeBatch sObject className. executeBatch sObject className ID Executes the specified class as a batch Apex job.000 total records retrieved and the total number of SOQL queries issued. see Database Batch Apex Objects and Methods.000 total records 379 . Each executed emptyRecycleBin method counts against the governor limit for DML statements. getQueryLocator String query QueryLocator Creates a QueryLocator object used in batch Apex or Visualforce. You can't use getQueryLocator with any query that contains an aggregate function. Integer ID scope Executes the specified class as a batch Apex job. Note: The class called by the executeBatch method implements the execute method. getQueryLocator sObject [] listOfQueries QueryLocator Creates a QueryLocator object used in batch Apex or Visualforce. Each executed getQueryLocator method counts against the governor limit of 10. For more information. Note: The class called by the executeBatch method implements the execute method. For more information. to your organization’s data. Each executed insert method counts against the governor limit for DML statements. Apex classes and triggers saved (compiled) using API version 15. and why.DMLOptions opt_DMLOptions Adds one or more sObjects. insert is analogous to the INSERT statement in SQL. Apex classes and triggers saved (compiled) using API version 15. If you specify false for this parameter and a record fails. This method returns a result object that can be used to verify which records succeeded. which failed. insert is analogous to the INSERT statement in SQL. which failed.Reference Apex System Methods Name Arguments Return Type Description retrieved and the total number of SOQL queries issued. to your organization's data. such as assignment rule information or rollback behavior when errors occur during record insertions. 380 . If you specify false for this parameter and a record fails. This method returns a result object that can be used to verify which records succeeded. the remainder of the DML operation can still succeed. insert sObject recordToInsert Boolean opt_allOrNone | database. such as assignment rule information or rollback behavior when errors occur during record insertions.0 and higher produce a runtime error if you assign a String value that is too long for the field.0 and higher produce a runtime error if you assign a String value that is too long for the field. The optional opt_DMLOptions parameter specifies additional data for the transaction. The optional opt_allOrNone parameter specifies whether the operation allows partial success. The optional opt_allOrNone parameter specifies whether the operation allows partial success. such as individual accounts or contacts. insert sObject [] recordsToInsert SaveResult[] Boolean opt_allOrNone | database.DMLOptions opt_DMLOptions SaveResult Adds an sObject. the remainder of the DML operation can still succeed. such as an individual account or contact. and why. The optional opt_DMLOptions parameter specifies additional data for the transaction. if you generated savepoint SP1 first.Savepoint sp Void Restores the database to the state specified by the savepoint variable. For more information. • • For an example. such as in regular assignment statements and for loops. the static variables retain the values from the first run. You will receive a runtime error if you try to rollback the database additional times. Each executed query method counts against the governor limit for SOQL queries. then roll back to a savepoint that is not the last savepoint you generated. rollback System. Each rollback counts against the governor limit for DML statements.Reference Apex System Methods Name Arguments Return Type Description Each executed insert method counts against the governor limit for DML statements. If you try to run the trigger again. This method can be used wherever a static SOQL query can be used. Note the following: • If you set more than one savepoint. see Dynamic SOQL on page 172. see Transaction Control. 381 . Create new a sObject to insert after a rollback. For example. Note the following: • Static variables are not reverted during a rollback. savepoint SP2 after that. thus. Attempting to insert the sObject using the variable created before the rollback fails because the sObject variable has an ID.Savepoint Returns a savepoint variable that can be stored as a local variable. then used with the rollback method to restore the database to that point. setSavepoint System. the later savepoint variables become invalid. The ID on an sObject inserted after setting a savepoint is not cleared after a rollback. Any emails submitted since the last savepoint are also rolled back and not sent. cannot be updated. query String query sObject[] Creates a dynamic SOQL query at runtime. Updating or upserting the sObject using the same variable also fails because the sObject is not in the database and. from your organization's Recycle Bin. from your organization's Recycle Bin. 382 . because each trigger invocation is a new execution context. undelete is analogous to the UNDELETE statement in SQL. undelete RecordID ID Boolean opt_allOrNone UndeleteResult Restores an existing sObject record. The optional opt_allOrNone parameter specifies whether the operation allows partial success. and why. the remainder of the DML operation can still succeed. References to savepoints cannot cross trigger invocations.Reference Apex System Methods Name Arguments Return Type Description and then you rolled back to SP1. This method returns a result object that can be used to verify which records succeeded. If you specify false for this parameter and a record fails. undelete sObject [] recordsToUndelete UndeleteResult[] Boolean opt_allOrNone Restores one or more existing sObject records. You will receive a runtime error if you try to use it. the remainder of the DML operation can still succeed. such as individual accounts or contacts. Each executed undelete method counts against the governor limit for DML statements. and why. Each savepoint you set counts against the governor limit for DML statements. from your organization’s Recycle Bin. the variable SP2 would no longer be valid. undelete is analogous to the UNDELETE statement in SQL. see Transaction Control. undelete sObject recordToUndelete UndeleteResult Boolean opt_allOrNone Restores an existing sObject record. which failed. This method returns a result object that can be used to verify which records succeeded. such as an individual account or contact. which failed. The optional opt_allOrNone parameter specifies whether the operation allows partial success. If you declare a savepoint as a static variable then try to use it across trigger contexts you will receive a runtime error. undelete is analogous to the UNDELETE statement in SQL. Each executed undelete method counts against the governor limit for DML statements. such as an individual account or contact. • • For an example. If you specify false for this parameter and a record fails. Each executed undelete method counts against the governor limit for DML statements.Reference Apex System Methods Name Arguments Return Type Description The optional opt_allOrNone parameter specifies whether the operation allows partial success. and why.DMLOptions opt_DMLOptions Database. which failed. If you specify false for this parameter and a record fails. and why. update sObject recordToUpdate Boolean opt_allOrNone | database. such as assignment rule information or rollback behavior when errors occur during record insertions. If you specify false for this parameter and a record fails. the remainder of the DML operation can still succeed. This method returns a result object that can be used to verify which records succeeded.0 and higher produce a runtime error if you assign a String value that is too long for the field. the remainder of the DML operation can still succeed. 383 . and why. such as an individual account or contact. undelete RecordIDs[] ID Boolean opt_allOrNone UndeleteResult [] Restores one or more existing sObject records. The optional opt_DMLOptions parameter specifies additional data for the transaction. undelete is analogous to the UNDELETE statement in SQL. such as individual accounts or contacts. the remainder of the DML operation can still succeed. in your organization's data. Each executed undelete method counts against the governor limit for DML statements. If you specify false for this parameter and a record fails.SaveResult Modifies an existing sObject record. update is analogous to the UPDATE statement in SQL. The optional opt_allOrNone parameter specifies whether the operation allows partial success. which failed. The optional opt_allOrNone parameter specifies whether the operation allows partial success. which failed. This method returns a result object that can be used to verify which records succeeded. This method returns a result object that can be used to verify which records succeeded. from your organization’s Recycle Bin. Apex classes and triggers saved (compiled) using API version 15. For example.0 and higher produce a runtime Boolean opt_allOrNone 384 . which failed.MyExternalId. Apex classes and triggers saved (compiled) using API version 15.DMLOptions The optional opt_allOrNone parameter specifies opt_DMLOptions whether the operation allows partial success. Schema. such [] as individual accounts or contactsinvoice statements. the remainder of the DML operation can still succeed. such as assignment rule information or rollback behavior when errors occur during record insertions. If you specify false for this parameter and a record fails. which failed. The External_ID_Field is of type Schema. Each executed update method counts against the governor limit for DML statements. the remainder of the DML operation can still succeed. If you specify false for this parameter and a record fails.SObjectField f = Account.SObjectField. update is analogous | to the UPDATE statement in SQL.0 and higher produce a runtime error if you assign a String value that is too long for the field.UpsertResult Creates a new sObject record or updates an existing sObject record within a single statement.SaveResult Modifies one or more existing sObject records.SObjectField External_ID_Field Database. and why. Boolean opt_allOrNone in your organization’s data. This method returns a result object that can be used to verify which records succeeded. This method returns a result object that can be used to verify which records succeeded. The optional opt_allOrNone parameter specifies whether the operation allows partial success. database. and why. Apex classes and triggers saved (compiled) using API version 15. using an optional custom field to determine the presence of existing objects. upsert sObject recordToUpsert Schema.Reference Apex System Methods Name Arguments Return Type Description Each executed update method counts against the governor limit for DML statements.Fields. a field token. update sObject [] recordsToUpdate Database. The optional opt_DMLOptions parameter specifies additional data for the transaction. that is. Find the token for the field by using the fields special method. Apex classes and triggers saved (compiled) using API version 15. The optional opt_allOrNone parameter specifies whether the operation allows partial success. Find Boolean opt_allOrNone the token for the field by using the fields special method.UpsertResult Cusing an optional custom field to determine the [] presence of existing objects. upsert sObject [] recordsToUpsert Database.MyExternalId. Each executed upsert method counts against the governor limit for DML statements.Fields.Reference Apex System Methods Name Arguments Return Type Description error if you assign a String value that is too long for the field. that is. 385 . For example: System. Each executed upsert method counts against the governor limit for DML statements. the remainder of the DML operation can still succeed. and why. For example. This method returns a result object that can be used to verify which records succeeded.SObjectField. If you specify false for this parameter and a record fails. Schema.QueryLocator object: Name getQuery Arguments Return Type String Description Returns the query used to instantiate the Database.QueryLocator object. See Also: Apex Data Manipulation Language (DML) Operations Understanding Execution Governors and Limits Database Batch Apex Objects and Methods Database. a field token. getQuery(). which failed. Schema.QueryLocator Method The following table lists the method for the Database.SObjectField External_ID_Field The External_ID_Field is of type Schema.assertEquals(QLReturnedFromStart. This is useful when testing the start method.0 and higher produce a runtime error if you assign a String value that is too long for the field.SObjectField f = Account. getQuery() ). the operation fails and an error message is returned. the property truncates String values that are too long. For API version 15. The ID 386 .allowFieldTruncation = true.Reference Apex System Methods Name Arguments Return Type Description Database. the value is truncated.DMLOptions object supports assignment rules for cases and leads.0 and later. The start method automatically locks the set of records in the batch.0 and earlier. specifying the truncation behavior of fields or assignment rule information.DMLOptions class has the following properties: • • • • • allowFieldTruncation Property assignmentRuleHeader Property emailHeader Property localeOptions Property optAllOrNone Property allowFieldTruncation Property The allowFieldTruncation property specifies the truncation behavior of strings. The Database. For example: Database. but not for accounts or territory management.0 and higher.DMLOptions(). for example.DMLOptions class to provide extra information during a transaction. The assignment rule can be active or inactive. The allowFieldTruncation property allows you to specify that the previous behavior. Note: The database. In Apex saved against API versions previous to 15. if a value is specified that is too large. If true.0 and later. DMLOptions is only available for Apex saved against API versions 15. if you specify a value for a string and that value is too large. The allowFieldTruncation property takes a Boolean value.DMLOptions dml = new Database. Database DMLOptions Properties Use the Database. The following are the options that can be set with the assignmentRuleHeader: Name assignmentRuleID Type ID Description Specify the ID of a specific assignment rule to run for the case or lead. You cannot use the FOR UPDATE keywords with a getQueryLocator query to lock a set of records. dml. which is the behavior in API versions 14. assignmentRuleHeader Property The assignmentRuleHeader property specifies the assignment rule to be used when creating a case or lead.getQueryLocator([SELECT Id FROM Account]). truncation. be used instead of the new behavior in Apex saved against API versions 15.0. The following example uses the useDefaultRule option: Database.DMLOptions emailHeader property enables you to specify additional information regarding the email that gets sent when one of the events occurs because of the code's execution. do not specify useDefaultRule. do not specify an assignmentRuleId.setOptions(dmo). dmo. this email can be automatically triggered by a number of events.useDefaultRule= true. If the value is not in correct ID format (15-character or 18-character Salesforce ID).Reference Apex System Methods Name Type Description can be retrieved by querying the AssignmentRule sObject. the system uses the default (active) assignment rule for the case or lead. the call fails and an exception is returned. In the Salesforce user interface. the Database. for example creating a case or resetting a user password. insert l.DMLOptions().DMLOptions().assignmentRuleHeader. insert l. l. dmo. The following are the options that can be set with the emailHeader property: Name triggerAutoResponseEmail Type Boolean Description Indicates whether to trigger auto-response rules (true) or not (false).DMLOptions dmo = new Database.setOptions(dmo).assignmentRuleHeader. If specified. Lead l = new Lead(company='ABC'.0 or later. lastname='Smith'). The following example uses the assignmentRuleID option: Database. emailHeader Property The Salesforce user interface allows you to specify whether or not to send an email when the following events occur: • • • • • • Creation of a new case or task Creation of a case comment Conversion of a case email to a contact New user email notification Lead queue email notification Password reset In Apex saved against API version 15. If this value is set to true. if there is an email address for the contact specified in ContactID. Lead l = new Lead(company='ABC'. l. lastname='Smith'). useDefaultRule Boolean If specified as true for a case or lead. when a case is created.assignmentRuleId= '01QD0000000EqAn'. If specified.DMLOptions dmo = new Database. for leads and cases. the email is 387 . Indicates whether to trigger email that is sent to users in the organization (true) or not (false).' If the value is further qualified by a country. leads.triggerAutoResponseEmail = true. A group event is an event for which IsGroupEvent is true. editing.com'. or deleting a contact for a case. dlo.Reference Apex System Methods Name Type Description sent to that address.DMLOptions(). for example 'fr' or 'en. adding comments to a case. Database. In the Salesforce user interface. Note the following behaviors for group event email sent through Apex: • • • Sending a group event invitation to a user respects the triggerUserEmail option Sending a group event invitation to a lead or contact respects the triggerOtherEmail option Email sent when updating or deleting a group event also respects the triggerUserEmail and triggerOtherEmail options. the triggerAutoResponseEmail option is specified: Account a = new Account(name='Acme Plumbing'). the string for the United States is 'en_US'. The EventAttendee object tracks the users. triggerOtherEmail Boolean Indicates whether to trigger email outside the organization (true) or not (false). see What languages does Salesforce support? in the Salesforce online help. and the string for French Canadian is 'fr_CA. In the Salesforce user interface. the email is sent to the address specified in SuppliedEmail. Case ca = new Case(subject='Plumbing Problems'. this email can be automatically triggered by creating.' For example. for example 'US' or 'UK. The first two characters are always an ISO language code. dlo). insert c.lastname='Plumber'. resetting a password. or creating or modifying a task. The value must be a valid user locale (language and country). triggerUserEmail Boolean In the following example.insert(ca. Contact c = new Contact(email='jplumber@salesforce. 2-5 characters long. 388 . this email can be automatically triggered by a number of events. database. or contacts that are invited to a group event.DMLOptions dlo = new Database. contactid=c. creating a new user.EmailHeader. insert a. as appropriate localeOptions Property The localeOptions property specifies the language of any labels that are returned by Apex. such as de_DE or en_GB. firstname='Joe'. accountid=a. then the string also has an underscore (_) and another ISO country code.' For a list of the languages that Salesforce supports.id). If not. The value is a String. Email sent through Apex because of a group event includes additional behaviors.id). they work on a specific instance of an EmptyRecyclelBinResult object. This property is available in Apex saved against Salesforce. Returns the ID of the record or sObject you attempted to deleted. otherwise false. The full list of status codes is available in the WSDL file for your organization (see Downloading Salesforce WSDLs and Client Authentication Certificates in the Salesforce online help.Reference Apex System Methods optAllOrNone Property The optAllOrNone property specifies whether the operation allows for partial success. the second with the second. Returns a code that characterizes the error. 389 .Error objects is returned.emptyRecycleBin method. Each object in the list corresponds to either a record Id or an sObject passed as the parameter in the Database.EmptyRecycleBinResult objects is returned by the Database. The first index in the EmptyRecycleBinResult list matches the first record or sObject specified in the list. All DML operations that are executed with their database system method form return an error object if they fail. If optAllOrNone is set to true. Apex provides a set of classes that expose methods for JSON serialization and deserialization.emptyRecycleBin method.com API version 20. Returns true if the record or sObject was successfully removed from the Recycle Bin. The following table describes the classes available. The following are all instance methods.error object contains information about an error that occurred.Errors [] Description If an error occurred during the delete for this record or sObject.0 and later. Name getErrors Return Type Database. None of these methods take any arguments. Database EmptyRecycleBinResult Methods A list of Database. a list of one or more Database. getId ID Boolean isSuccess Database Error Object Methods A Database. The default for this property is false and successfully processed records are committed while records with errors aren't. and so on. all changes are rolled back if any record causes errors. during a DML operation or other operation. If no errors occurred.) JSON Support JavaScript Object Notation (JSON) support in Apex enables the serialization of Apex objects into JSON format and the deserialization of serialized JSON content. this list is empty. that is. All error objects have access to the following methods: Name getMessage getStatusCode Arguments Return Type String StatusCode Description Returns the error message text. JSONParser The System. of managed packages can be serialized from code that is external to the managed package. Objects that are instances of Apex classes defined in the managed package can't be serialized.JSONParser and you attempt to create this object. 390 . use a local variable instead in your method. Usage Use the methods in the System. when deserialized.JSON class. • • • • • • JSON Methods Contains methods for serializing Apex objects into JSON format and deserializing JSON content that was serialized using the serialize method in this class. JSON Support Considerations • JSON serialization and deserialization support is available for sObjects (standard objects and custom objects). that has a member variable of type System. The System. and instances of your Apex classes. a Map<Object. To use JSONParser in a serializable class.JSON Description Contains methods for serializing Apex objects into JSON format and deserializing JSON content that was serialized using the serialize method in this class.JSONGenerator System. The object gets serialized and deserialized as the parent type and any fields that are specific to the subtype are lost. Contains methods used to serialize Apex objects into JSON content using the standard JSON encoding. Apex primitive and collection types. change their type. System. and so on). Deserialized Map objects whose keys are not strings won't match their corresponding Map objects before serialization. An object that has a reference to itself won’t get serialized and causes a JSONException to be thrown.Reference Apex System Methods Class System. sObject> will become a Map<String.JSONToken enumeration contains the tokens used for JSON parsing. Represents a parser for JSON-encoded content. DeleteResult. When an object is declared as the parent type but is set to an instance of the subtype. you’ll receive an exception. If you have a serializable class. Methods in these classes throw a JSONException if an issue is encountered during execution. Key values are converted into strings during serialization and will. Only custom objects.JSONParser data type isn’t serializable. For example.JSON class to perform round-trip JSON serialization and deserialization of Apex objects. which are sObject types. Methods The following are static methods of the System. Reference graphs that reference the same object twice are deserialized and cause multiple copies of the referenced object to be generated. sObject>. some data may be lost. return types of Database methods (such as SaveResult. such as a Visualforce controller. All attributes in the JSON string must be present in the specified type. Any type Deserializes the specified JSON string into an Apex object of the specified type.com API version 24.Type apexType Any type Deserializes the specified JSON string into an Apex object of the specified type. The jsonString argument is the JSON content to deserialize.1).deserializeStrict( '{"make":"SFDC". System. for Apex saved using Salesforce.assertEquals(n.JSONParser Returns a new JSON parser. this method throws a run-time exception."year":"2020"}'. Decimal. If the JSON content to parse contains attributes not present in the Apex type specified in the argument. The jsonString argument is the JSON content to deserialize.1'. such as a missing field or object.Reference Apex System Methods Method Arguments Return Type Description createGenerator Boolean pretty System. The apexType argument is the Apex type of the object that this method creates after deserializing the JSON content. System. However. public String year. createParser String jsonString The jsonString argument is the JSON content to parse. deserialize String jsonString System. } public void parse() { Car c = (Car)JSON. Set to true to create indented content. 100.deserialize( '100. If the JSON content to parse contains attributes not present in the Apex type specified in the argument. such as a missing field or object.class).Type apexType deserializeStrict String jsonString System. The following example deserializes a Decimal value. which this example also defines. public class Car { public String make.0 or earlier. this method ignores these attributes and parses the rest of the JSON content.JSONGenerator Returns a new JSON generator. The following example deserializes a JSON string into an object of a user-defined type represented by the Car class. 391 . Decimal n = (Decimal)JSON. The pretty argument determines whether the JSON generator creates JSON content in pretty-print format with the content indented. this method throws a run-time exception for missing attributes. The apexType argument is the Apex type of the object that this method creates after deserializing the JSON content. The jsonString argument is the JSON content to deserialize.get('depth')). ' + '"depth" : 2.assertEquals( 2.deserializeUntyped(jsonInput). '2020').5.get('right')).5 . a2. a[0]). m.get('width')).assertEquals( 392 .\n' + ' "accessories" : [ "powerCord". Object>) JSON.assertEquals( 'door handle2'. System.2.make. dim.get('height')). Object> m = (Map<String. System. List<Object> a = (List<Object>)m.assertEquals( 'An appliance'.45. dim. 'SFDC').get('left')). ' + '{ "right":"door handle1".year. System. Object> dim = (Map<String.\n' + ' "dimensions" : ' + '{ "height" : 5.assertEquals( 5. Map<String.0 . System. System. System. a2. It then verifies the deserialized values. ' + '"width" : 3.\n' + ' "inventory" : 2000.\n' + ' "isShipped" : true. } deserializeUntyped String jsonString Any type Deserializes the specified JSON string into collections of primitive data types. Object>)m.assertEquals(c.Reference Apex System Methods Method Arguments Return Type Description Car.assertEquals( 'door handle1'. The following example deserializes a JSON representation of an appliance object into a map that contains primitive data types and further collections of primitive types. System.2 }. System.\n' + ' "type" : null. String jsonInput = '{\n' + ' "description" :"An appliance".\n' + ' "price" : 1023. System. System. Object> a2 = (Map<String.get('dimensions').get('type')). Object>)a[1]. dim.assertEquals( 3.get('description')). ' + '"left":"door handle2" } ]. Map<String.assertEquals(null.0.\n' + ' "modelNumber" : "123"\n' + '}'. System.get('accessories').assertEquals(c. m.class). Map<String.assertEquals('powerCord'. newInstance( 1. // Add the invoices to a list. Sample: Serializing and Deserializing a List of Invoices This sample creates a list of InvoiceStatement objects and serializes the list. List<InvoiceStatement> invoices = new List<InvoiceStatement>().valueOf(dt). Next.assertEquals( 1023. m. 393 . str).now().Datetime.newInstance( 2011. System. Datetime statementDate.assertEquals( '"2011-03-22T08:15:18.Datetime.000Z"'. 22).500). Time. System. totalPrice = price. public class JSONRoundTripSample { public class InvoiceStatement { Long invoiceNumber. 15.serialize(dt).newInstance( Date.get('price')).valueOf(dt). // Create a few invoices. Datetime dt. serialize Any type object String Serializes Apex objects into JSON content.Reference Apex System Methods Method Arguments Return Type Description 2000. InvoiceStatement inv2 = new InvoiceStatement(2. invoices. 0)). 3. Decimal totalPrice.assertEquals( '123'. public InvoiceStatement(Long i. Decimal price) { invoiceNumber = i. statementDate = dt.get('isShipped')). The object argument is the Apex object to serialize. Datetime dt = Datetime.get('inventory')). The object argument is the Apex object to serialize. m. InvoiceStatement inv1 = new InvoiceStatement(1. } } public static void SerializeRoundtrip() { Datetime dt = Datetime. System. System. serializePretty Any type object String Serializes Apex objects into JSON content and generates indented content using the pretty-print format. The following example serializes a new Datetime value.assertEquals( true.get('modelNumber')). 18. the serialized JSON string is used to deserialize the list again and the sample verifies that the new list contains the same invoices that were present in the original list. m.1000).45. String str = JSON. m.add(inv1). formatGmt('MM/dd/yyyy HH:mm:ss. for (InvoiceStatement deserializedInvoice :deserializedInvoices) { system.assertEquals(invoices.serialize(invoices). ' + deserializedInvoice.statementDate.totalPrice).debug('Deserialized:' + deserializedInvoice. this method closes the JSON generator if it isn't closed already. Usage Since the JSON encoding that's generated by Apex through the serialization method in the System.size(). List<InvoiceStatement>. Method close Arguments Return Type Void Description Closes the JSON generator.add(inv2).invoiceNumber + '.formatGmt('MM/dd/yyyy HH:mm:ss.deserialize(JSONString. String JSONString = JSON.JSONGenerator class is provided to enable the generation of standard JSON-encoded content.totalPrice).' + deserializedInvoice. System.Reference Apex System Methods invoices. the System. deserializedInvoices.SSS') + '.statementDate. Also. } } } See Also: Type Methods JSONGenerator Methods Contains methods used to serialize Apex objects into JSON content using the standard JSON encoding. writeBlob 394 .debug('Original:' + invoices[i].SSS') + '. isClosed Boolean Blob blobValue Void Returns true if the JSON generator is closed.JSON class isn't identical to the standard JSON encoding in some cases. // Deserialize the list of invoices from the JSON string. returns false. Integer i=0. getAsString String Returns the generated JSON content. i++. No more content can be written after the JSON generator is closed. List<InvoiceStatement> deserializedInvoices = (List<InvoiceStatement>)JSON. System.' + invoices[i].invoiceNumber + '. // Serialize the list of InvoiceStatement objects.JSONGenerator class.debug('Serialized list of invoices into JSON format: ' + JSONString).size()). Methods The following are instance methods of the System. Writes the specified Blob value as a base64-encoded string. otherwise. system. ' + invoices[i].class). Writes a field name and value pair using the specified field name and double value. Writes the specified double value.Reference Apex System Methods Method writeBlobField Arguments Return Type Description Writes a field name and value pair using the specified field name and BLOB value. String fieldName Void Blob blobValue writeBoolean Boolean blobValue Void writeBooleanField String fieldName Void Boolean booleanValue writeDate writeDateField Date dateValue Void String fieldName Void Date dateValue Writes the specified date value in the ISO-8601 format. Writes a field name and value pair using the specified field name and Boolean value. Writes the specified date and time value in the ISO-8601 format. writeDateTime Datetime datetimeValue Void writeDateTimeField String fieldName Void Datetime datetimeValue writeEndArray writeEndObject writeFieldName writeId writeIdField Void Void String fieldName Void ID identifier Void String fieldName Void Id identifier writeNull writeNullField writeNumber writeNumber writeNumber writeNumber writeNumberField Void String fieldName Void Decimal number Double number Integer number Long number Void Void Void Void String fieldName Void Decimal number writeNumberField String fieldName Void Double number 395 . The date value is written in the ISO-8601 format. Writes the specified ID value. Writes a field name and value pair using the specified field name and date value. Writes the ending marker of a JSON array (']'). Writes the JSON null literal value. Writes the specified integer value. Writes the specified long value. Writes a field name and value pair using the specified field name and decimal value. Writes the specified decimal value. The date and time value is written in the ISO-8601 format. Writes the specified Boolean value. Writes the ending marker of a JSON object ('}'). Writes a field name. Writes a field name and value pair using the specified field name and the JSON null literal value. Writes a field name and value pair using the specified field name and identifier value. Writes a field name and value pair using the specified field name and date and time value. JSONGenerator Sample This example generates a JSON string by using the methods of JSONGenerator. Writes a field name and value pair using the specified field name and long value. gen. String fieldName Void Integer number writeNumberField String fieldName Void Long number writeObject writeObjectField Any type object Void String fieldName Void Any type object writeStartArray writeStartObject writeString Void Void String stringValue Void writeStringField String fieldName Void String stringValue writeTime writeTimeField Time timeValue Void String fieldName Void Time timeValue Writes the specified time value in the ISO-8601 format.writeNumberField('abc'.21). // Create an object to write to the JSON string. } } static void generateJSONContent() { // Create a JSONGenerator object. Writes a field name and value pair using the specified field name and time value in the ISO-8601 format. intlist. Writes the starting marker of a JSON object ('{'). 396 . 1. Writes the starting marker of a JSON array ('['). Writes a field name and value pair using the specified field name and string value.add(2).add(1).add(3). // Pass true to the constructor for pretty print formatting.writeStartObject(). intlist. // Create a list of integers to write to the JSON string. public class JSONGeneratorSample{ public class A { String str.createGenerator(true). JSONGenerator gen = JSON. public A(String s) { str = s. Writes the specified Apex object in JSON format Writes a field name and value pair using the specified field name and Apex object. List<integer> intlist = new List<integer>(). // Write data to the JSON string. gen.Reference Apex System Methods Method writeNumberField Arguments Return Type Description Writes a field name and value pair using the specified field name and integer value. Writes the specified string value. A x = new A('X'). intlist. JSONParser methods to parse a response that's returned from a call to an external service that is in JSON format.\n' + ' "ghi" : {\n' + ' "aaa" : [ 1.\n' + ' "def" : "xyz". intlist). gen. such as a JSON-encoded response of a Web service callout.writeObjectField('aaa'. gen.21.Reference Apex System Methods gen. 397 . gen. 3 ]\n' + ' }.writeStringField('def'. The current token must be of type JSONToken. } } JSONParser Methods Represents a parser for JSON-encoded content.getAsString().writeEndObject(). // Get the JSON string.assertEquals('{\n' + ' "abc" : 1. 2. You can retrieve the cleared token by calling getLastClearedToken.VALUE_TRUE or JSONToken. After this method is called. Method clearCurrentToken Arguments Return Type Void Description Removes the current token. Usage Use the System. getBooleanValue Boolean Returns the current token as a Boolean value. gen. Methods The following are instance methods of the System.writeEndObject(). getBlobValue Blob Returns the current token as a BLOB value.VALUE_FALSE. gen.writeFieldName('Object A'). pretty).writeObject(x). gen. 'xyz').JSONParser class. a call to hasCurrentToken returns false and a call to getCurrentToken returns null.\n' + ' "Object A" : {\n' + ' "str" : "X"\n' + ' }\n' + '}'.writeFieldName('ghi'). String pretty = gen.VALUE_STRING and must be Base64-encoded. System. The current token must be of type JSONToken.writeStartObject(). gen. nextToken() != null) { System. String fieldName = parser. this method returns the field name that precedes this token. // Advance to the next value. String fieldValue = parser.getBooleanValue(). parser. If the current token is a value.Reference Apex System Methods Method Arguments Return Type Description The following example parses a sample JSON string and retrieves a Boolean value. // Advance to the start object marker. // Get the field name for the current value. // Get the textual representation // of the value. If the current token is of type JSONToken. String JSONContent = '{"firstName":"John"}'. getCurrentName String Returns the name associated with the current token. String JSONContent = '{"firstName":"John"}'. // Advance to the next value.nextToken(). // Advance to the next token. parser. String JSONContent = '{"isActive":true}'. // Get the Boolean value. For other values such as array values or root-level values.getText(). this method returns null.createParser(JSONContent). parser. // Advance to the start object marker.createParser(JSONContent). JSONParser parser = JSON.FIELD_NAME. It advances to the field value and retrieves its corresponding field name. } 398 .createParser(JSONContent). while (parser.debug('Current token: ' + parser.nextValue().JSONToken Returns the token that the parser currently points to or null if there's no current token. The following example parses a sample JSON string. parser. JSONParser parser = JSON.nextValue(). JSONParser parser = JSON. this method returns the same value as getText. Boolean isActive = parser. getCurrentToken System.nextToken().getCurrentToken()).getCurrentName(). The following example iterates through all the tokens in a sample JSON string. The current token must be of type JSONToken. 399 .getDateValue().VALUE_NUMBER_FLOAT or JSONToken.createParser(JSONContent). // Advance to the start object marker. // Advance to the next value. The following example parses a sample JSON string and retrieves a Datetime value. // Advance to the start object marker.nextValue().VALUE_NUMBER_INT and is a numerical value that can be converted to a value of type Decimal. parser. // Get the date of birth. parser. The following example parses a sample JSON string and retrieves a Date value. Datetime transactionDate = parser.createParser(JSONContent). // Advance to the start object marker. Date dob = parser. String JSONContent = '{"transactionDate":"2011-03-22T13:01:23"}'. JSONParser parser = JSON. The current token must be of type JSONToken.nextToken(). // Advance to the next value. String JSONContent = '{"dateOfBirth":"2011-03-22"}'. The following example parses a sample JSON string and retrieves a Decimal value.nextToken(). String JSONContent = '{"GPA":3. getDecimalValue Decimal Returns the current token as a decimal value. parser. JSONParser parser = JSON.createParser(JSONContent). getDateValue Date Returns the current token as a date value.nextToken(). parser.Reference Apex System Methods Method getDatetimeValue Arguments Return Type Datetime Description Returns the current token as a date and time value. // Get the transaction date.8}'. The current token must be of type JSONToken.nextValue().getDatetimeValue(). // Advance to the next value. JSONParser parser = JSON.VALUE_STRING and must represent a Datetime value in the ISO-8601 format.VALUE_STRING and must represent a Date value in the ISO-8601 format. parser. getIdValue(). String JSONContent = '{"recordCount":10}'. ID recordID = parser.8}'. parser.nextToken(). JSONParser parser = JSON. getIntegerValue Integer Returns the current token as an integer value.VALUE_NUMBER_FLOAT and is a numerical value that can be converted to a value of type Double.createParser(JSONContent). // Advance to the start object marker. JSONParser parser = JSON. parser.VALUE_NUMBER_INT and must represent an Integer. getDoubleValue Double Returns the current token as a double value. // Get the GPA score. parser. The current token must be of type JSONToken. The current token must be of type JSONToken. // Get the GPA score. 400 .getDecimalValue(). String JSONContent = '{"GPA":3. The following example parses a sample JSON string and retrieves a Double value. // Advance to the start object marker.nextValue(). // Advance to the next value. // Advance to the start object marker.createParser(JSONContent). getIdValue ID Returns the current token as an ID value. // Get the record ID. JSONParser parser = JSON. Decimal gpa = parser.Reference Apex System Methods Method Arguments Return Type Description parser.VALUE_STRING and must be a valid ID. Double gpa = parser. The following example parses a sample JSON string and retrieves an ID value. // Advance to the next value. The following example parses a sample JSON string and retrieves an Integer value. The current token must be of type JSONToken.nextToken().nextValue().createParser(JSONContent).nextValue().getDoubleValue(). parser. String JSONContent = '{"recordId":"001R0000002nO6H"}'. 401 . getLongValue Long Returns the current token as a long value.createParser(JSONContent). parser.getIntegerValue(). and therefore this method returns null. parser. parser. // Advance to the next value. parser. // Advance to the start object marker. The following example parses a sample JSON string and retrieves a Datetime value. Time arrivalTime = parser. if nextToken has not been called yet for the first time or if the parser has reached the end of the input stream. getTimeValue Time Returns the current token as a time value.nextToken(). // Advance to the next value.nextToken(). For an example. // Advance to the next value.getLongValue().nextToken().JSONToken Returns the last token that was cleared by the clearCurrentToken method. getLastClearedToken System. No current token exists. // Get the record count. Long count = parser. The current token must be of type JSONToken.VALUE_STRING and must represent a Time value in the ISO-8601 format. getText String Returns the textual representation of the current token or null if there's no current token. The current token must be of type JSONToken.nextValue().Reference Apex System Methods Method Arguments Return Type Description parser.getTimeValue(). JSONParser parser = JSON. see getCurrentName on page 398.nextValue(). parser. The following example parses a sample JSON string and retrieves a Long value. Integer count = parser. // Get the record count. String JSONContent = '{"recordCount":2097531021}'.nextValue(). // Get the arrival time. // Advance to the start object marker. String JSONContent = '{"arrivalTime":"18:05"}'.createParser(JSONContent).VALUE_NUMBER_INT and is a numerical value that can be converted to a value of type Long . JSONParser parser = JSON. For an example. parser. // Make calls to nextToken() // to point to the second // start object marker. However. this method ignores these attributes and parses the rest of the JSON content.JSONToken Returns the next token or null if the parser has reached the nextValue System.nextToken(). public String phone. readValueAs System. Advances the stream enough to determine the type of the next token. if any. nextToken System. including a JSON array and object start and end markers. If the JSON content to parse contains attributes not present in the Apex type specified in the argument. see getCurrentName on page 398. if any. you must create a new Apex class as follows: public class Person { public String name. otherwise.' + '"phone":"555-1212"}}'. The following example parses a sample JSON string and retrieves a Datetime value. returns false. // Retrieve the Person object // from the JSON string. String JSONContent = '{"person":{' + '"name":"John Smith".Reference Apex System Methods Method hasCurrentToken Arguments Return Type Boolean Description Returns true if the parser currently points to a token.0 or earlier. The apexType argument specifies the type of the object that this method returns after deserializing the current value. Advances the stream enough to determine the type of the next token that is of a value type. such as a missing field or object. Before being able to run this sample. JSONParser parser = JSON. for Apex saved using Salesforce. parser. } Next.com API version 24. insert the following sample in a class method: // JSON string that contains a Person object.nextToken(). this method throws a run-time exception for missing attributes. parser.Type Any type apexType Deserializes JSON content into an object of the specified Apex type and returns the deserialized object. end of the input stream.nextToken().JSONToken Returns the next token that is a value type or null if the parser has reached the end of the input stream.createParser(JSONContent). For an example. 402 . see getCurrentName on page 398. assertEquals( obj. readValueAsStrict System. 'John Smith'). System.name. System. } Next. String JSONContent = '{"person":{' + '"name":"John Smith".nextToken().readValueAsStrict( Person. If the JSON content to parse contains attributes not present in the Apex type specified in the argument. parser. All attributes in the JSON content must be present in the specified type. Person obj = (Person)parser.assertEquals( obj. insert the following sample in a class method: // JSON string that contains a Person object. parser.Type Any type apexType Deserializes JSON content into an object of the specified Apex type and returns the deserialized object. parser. 'John Smith'). public String phone.createParser(JSONContent).START_OBJECT that the parser currently points to. Before being able to run this sample. '555-1212'). System.Reference Apex System Methods Method Arguments Return Type Description Person obj = (Person)parser.assertEquals( obj. such as a missing field or object. 403 . System.phone.START_ARRAY and JSONToken.phone. JSONParser parser = JSON. // Retrieve the Person object // from the JSON string. this method throws a run-time exception.class). '555-1212'). skipChildren Void Skips all child tokens of type JSONToken. The following example parses a sample JSON string and retrieves a Datetime value.nextToken().assertEquals( obj.class).nextToken(). // Make calls to nextToken() // to point to the second // start object marker.The apexType argument specifies the type of the object that this method returns after deserializing the current value. you must create a new Apex class as follows: public class Person { public String name.' + '"phone":"555-1212"}}'.readValueAs( Person.name. cheenath.setEndPoint(endpoint). JSONParser parser = JSON."ProductName":"Eraser"}]."Quantity":5.5.com/tutorial/sfdc/sample1/response.getDoubleValue(). Since each invoice contains line items. To do this. // Set the HTTP verb to GET. Add this sample code to a class to use it."Quantity":1.getBody()). parser. This example makes a callout to a Web service that returns a response in JSON format.0. } } system."statementDate":"2011-10-04T16:58:54.' + '{"UnitPrice":2. request. HttpRequest request = new HttpRequest().createParser(response.getBody())."Quantity":2. while (parser.0. HttpResponse response = httpProtocol. the class that represents the corresponding line item type. // The response is in JSON format. which is the same JSON string returned by the callout in the previous example. The parsed objects are instances of the Invoice class that is defined as an inner class."lineItems":[' + '{"UnitPrice":1. // Compute the grand total price for all invoices.0.' + '"invoiceNumber":1}.858Z".0."ProductName":"Pen"}]. */ // Parse JSON response to get all the totalPrice field values. System."ProductName":"Ruler"}. request.FIELD_NAME) && (parser. public static void parseJSONString() { String jsonStr = 404 . grandTotal += parser."ProductName":"Notebook"}. is also defined as an inner class.php'.5.Reference Apex System Methods Sample: Parsing a JSON Response from a Web Service Callout This example shows how to parse a JSON-formatted response using JSONParser methods. the response is parsed to get all the totalPrice field values and compute the grand total price.' + '{"UnitPrice":1. you must add the Web service endpoint URL as an authorized remote site in the Salesforce user interface.' + '{"totalPrice":11. // Create HTTP request to send.5. the LineItem class. Double grandTotal = 0.debug(response.setMethod('GET')."invoiceNumber":2}' + ']}'.debug('Grand total=' + grandTotal). Before you can run this sample.0.858Z". the entire string is parsed into Invoice objects using the readValueAs method. String endpoint = 'http://www.getText() == 'totalPrice')) { // Get the value.0."ProductName":"Pencil"}."Quantity":1. // Set the endpoint URL. public class JSONParserUtil { @future(callout=true) public static void parseJSONResponse() { Http httpProtocol = new Http().0."statementDate":"2011-10-04T16:58:54.0.nextToken(). // Send the HTTP request and get the response.send(request). Next."Quantity":1.5. } } Sample: Parsing a JSON String and Deserializing It into Objects This example uses a hardcoded JSON string. It also uses the skipChildren method to skip the child array and child objects and to be able to parse the next sibling invoice in the list. /* The JSON response returned is the following: String s = '{"invoiceList":[' + '{"totalPrice":5.getCurrentToken() == JSONToken.nextToken() != null) { if ((parser.' + '{"UnitPrice":0.5. log in to Salesforce and select Your Name > Setup > Security Controls > Remote Site Settings."lineItems":[' + '{"UnitPrice":6. In this example. List<LineItem> lineItems."Quantity":1.size())."ProductName":"Ruler"}.nextToken() != null) { // Start at the array of invoices. public DateTime statementDate."lineItems":[' + '{"UnitPrice":1."ProductName":"Notebook"}.0.createParser(jsonStr).getCurrentToken() == JSONToken.START_OBJECT) { // Read entire invoice object. public Double quantity. // Parse entire JSON response. public String productName. system."Quantity":2.0.serialize(inv). List<LineItem> liList) { totalPrice = price. Long invNumber. serialize again to verify what was parsed.debug('Serialized invoice: ' + s). public class Invoice { public Double totalPrice. lineItems = liList."Quantity":5. system.Reference Apex System Methods '{"invoiceList":[' + '{"totalPrice":5.' + '{"UnitPrice":1. public Long invoiceNumber.0. This token is returned when ']' is encountered.JSONToken Enum Enum Value END_ARRAY Description The ending of an array value.getCurrentToken() == JSONToken. String s = JSON."statementDate":"2011-10-04T16:58:54.5. invoiceNumber = invNumber.5.debug('Invoice number: ' + inv."lineItems":[' + '{"UnitPrice":6."Quantity":1.skipChildren().' + '"invoiceNumber":1}.invoiceNumber).0. system."ProductName":"Eraser"}].readValueAs(Invoice.5. if (parser."invoiceNumber":2}' + ']}'. // Skip the child start array and start object markers.clone().858Z". } } } } } // Inner classes used for serialization by readValuesAs(). 405 . while (parser. JSONParser parser = JSON."ProductName":"Pencil"}."Quantity":1.5.0. including its array of line items. } } public class LineItem { public Double unitPrice. Invoice inv = (Invoice)parser.0.0.class).nextToken() != null) { // Advance to the start object marker to // find next invoice statement object.START_ARRAY) { while (parser.858Z". parser.' + '{"UnitPrice":2.5.lineItems."statementDate":"2011-10-04T16:58:54."ProductName":"Pen"}]. } The System. public Invoice(Double price. DateTime dt. if (parser.' + '{"UnitPrice":0. // For debugging purposes. statementDate = dt.debug('Size of list items: ' + inv.' + '{"totalPrice":11. This token is returned when '[' is encountered. A value that corresponds to the “true” string literal.Reference Apex System Methods Enum Value END_OBJECT FIELD_NAME NOT_AVAILABLE START_ARRAY START_OBJECT VALUE_EMBEDDED_OBJECT Description The ending of an object value. The literal “false” value. The format of the limits methods is as follows: myDMLLimit = Limits. An integer value. The start of an object value. VALUE_FALSE VALUE_NULL VALUE_NUMBER_FLOAT VALUE_NUMBER_INT VALUE_STRING VALUE_TRUE See Also: Type Methods Limits Methods Because Apex runs in a multitenant environment. The requested token isn't available. A string value. A float value. This token is returned when '}' is encountered. 406 . This token is returned when '{' is encountered. An embedded object that isn't accessible as a typical object structure that includes the start and end object tokens START_OBJECT and END_OBJECT but is represented as a raw object. The Limits methods return the specific limit for the particular governor.getDMLStatements(). The literal “null” value. There are two versions of every method: the first returns the amount of the resource that has been used while the second version contains the word limit and returns the total amount of the resource that is available. A string token that is a field name. such as the number of calls of a method or the amount of heap size remaining. None of the Limits methods require an argument. the Apex runtime engine strictly enforces a number of limits to ensure that runaway Apex does not monopolize shared resources. The start of an array value. See Understanding Execution Governors and Limits on page 214. getLimitAggregateQueries getCallouts getLimitCallouts getChildRelationshipsDescribes getLimitChildRelationshipsDescribes Integer getCpuTime Integer getLimitCpuTime getDMLRows Integer Returns the number of records that have been processed with any DML statement (insertions. Returns the number of field describe calls that have been made. Returns the total number of child relationship objects that can be returned. Returns the total number of DML statements or the database. Returns the total number of email invocation (such as sendEmail) that can be called.EmptyRecycleBin method) that have been called. Returns the number of email invocations (such as sendEmail) that have been called. Returns the time limit (in milliseconds) of CPU usage in the current transaction.EmptyRecycleBin methods that can be called. update or the database. Returns the total number of records that can be processed with any DML statement or the database. Returns the number of DML statements (such as insert. getLimitDMLRows Integer getDMLStatements Integer getLimitDMLStatements Integer Integer Integer Integer Integer getEmailInvocations getLimitEmailInvocations getFieldsDescribes getLimitFieldsDescribes 407 .EmptyRecycleBin method. Returns the total number of Web service statements that can be processed. Returns -1 if called in a context where there is no CPU time limit such as in a test method. Returns the number of Web service statements that have been processed. Returns the CPU time (in milliseconds) accumulated on the Salesforce servers in the current transaction. deletions) or the database. Returns the number of child relationship objects that have been returned. Returns the total number of aggregate queries that can be processed with SOQL query statements. Returns the total number of field describe calls that can be made.EmptyRecycleBin method.Reference Apex System Methods Name getAggregateQueries Return Type Integer Integer Integer Integer Integer Description Returns the number of aggregate queries that have been processed with any SOQL query statement. getLimitFieldSetsDescribes getFindSimilarCalls getLimitFindSimilarCalls Integer getFutureCalls Integer Integer Integer Integer Integer Integer Integer Integer Integer Integer Integer Integer Integer getLimitFutureCalls getHeapSize getLimitHeapSize getQueries getLimitQueries getPicklistDescribes getLimitPicklistDescribes getQueryLocatorRows getLimitQueryLocatorRows getQueryRows getLimitQueryRows getRecordTypesDescribes 408 .Reference Apex System Methods Name getFieldSetsDescribes Return Type Integer Integer Integer Description Returns the number of field set describe calls that have been made.getQueryLocator method. but is tracked as the number of SOSL queries issued. Returns the number of methods with the future annotation that have been executed (not necessarily completed). Returns the total amount of memory (in bytes) that can be used for the heap. Returns the number of records that have been returned by issuing SOQL queries. Returns the approximate amount of memory (in bytes) that has been used for the heap. Returns the total number of SOQL queries that can be issued. Returns the total number of field set describe calls that can be made. Returns the number of RecordTypeInfo objects that have been returned. Returns the total number of records that can be returned by issuing SOQL queries. The number of findSimilar methods is no longer a separate limit. Returns the same value as getSoslQueries. Returns the number of records that have been returned by the Database. The number of findSimilar methods is no longer a separate limit. This method is deprecated. Returns the number of SOQL queries that have been issued. but is tracked as the number of SOSL queries issued. Returns the total number of records that have been returned by the Database. Returns the total number of methods with the future annotation that can be executed (not necessarily completed). Returns the number of PicklistEntry objects that have been returned. This method is deprecated.getQueryLocator method. Returns the total number of PicklistEntry objects that can be returned. Returns the same value as getLimitSoslQueries. getRunAs getLimitRunAs Integer getSavepointRollbacks Integer getLimitSavepointRollbacks Integer getSavepoints Integer getLimitSavepoints Integer getScriptStatements getLimitScriptStatements getSoslQueries getLimitSoslQueries Integer Integer Integer Integer Math Methods The following are the system static methods for Math. The number of setSavepoint methods is no longer a separate limit. This method is deprecated. This method is deprecated. Returns the same value as getDMLStatements. Returns the number of Apex statements that have executed.Reference Apex System Methods Name getLimitRecordTypesDescribes Return Type Integer Integer Description Returns the total number of RecordTypeInfo objects that can be returned. This method is deprecated. Returns the total number of Apex statements that can execute. Returns the same value as getLimitDMLStatements. Returns the same value as getLimitDMLStatements. This method is deprecated. The number of RunAs methods is no longer a separate limit. Returns the same value as getDMLStatements. Returns the absolute value of the specified Double. Returns the same value as getLimitDMLStatements. but is tracked as the number of DML statements issued. but is tracked as the number of DML statements issued. but is tracked as the number of DML statements issued. 409 . but is tracked as the number of DML statements issued. Name abs abs Arguments Decimal d Double d Return Type Decimal Double Description Returns the absolute value of the specified Decimal. but is tracked as the number of DML statements issued. This method is deprecated. The number of Rollback methods is no longer a separate limit. Returns the same value as getDMLStatements. Returns the total number of SOSL queries that can be issued. This method is deprecated. Returns the number of SOSL queries that have been issued. but is tracked as the number of DML statements issued. The number of RunAs methods is no longer a separate limit. The number of Rollback methods is no longer a separate limit. The number of setSavepoint methods is no longer a separate limit. The cube root of a negative value is the negative of the cube root of that value's magnitude. in the range of 0. Returns the arc tangent of an angle. Returns the smallest (closest to negative infinity) Double that is not less than the argument and is equal to a mathematical integer. Returns the cube root of the specified Double. Returns the arc sine of an angle. system. Returns the cube root of the specified Decimal. 42).0 through pi. in the range of -pi/2 through pi/2. The cube root of a negative value is the negative of the cube root of that value's magnitude. abs acos Long l Decimal d Double d Decimal d Double d Decimal d Double d Decimal x Decimal y Long Decimal Double Decimal Double Decimal Double Decimal Returns the absolute value of the specified Long. Integer I2 = math. in the range of -pi/2 through pi/2. Returns the smallest (closest to negative infinity) Decimal that is not less than the argument and is equal to a mathematical integer.abs(I). Converts rectangular coordinates (x and y) to polar (r and theta). Converts rectangular coordinates (x and y) to polar (r and theta).assertEquals(I2. For example: Integer I = -42. This method computes the phase theta by computing an arc tangent of x/y in the range of -pi to pi. This method computes the phase theta by computing an arc tangent of x/y in the range of -pi to pi. Returns the arc cosine of an angle. in the range of 0. Returns the arc tangent of an angle. Returns the arc sine of an angle. in the range of -pi/2 through pi/2. acos asin asin atan atan atan2 atan2 Double x Double y Double cbrt Decimal d Decimal cbrt Double d Double ceil Decimal d Decimal ceil Double d Double 410 .Reference Apex System Methods Name abs Arguments Integer i Return Type Integer Description Returns the absolute value of the specified Integer.0 through pi. Returns the arc cosine of an angle. in the range of -pi/2 through pi/2. The hyperbolic cosine of d is defined to be (ex + e-x)/2 where e is Euler's number. Returns Euler's number e raised to the power of the specified Double. Returns the logarithm (base 10) of the specified Decimal. system.6). Returns the largest (closest to positive infinity) Decimal that is not greater than the argument and is equal to a mathematical integer. 411 . Returns Euler's number e raised to the power of the specified Decimal. Returns the largest (closest to positive infinity) Double that is not greater than the argument and is equal to a mathematical integer. Returns the larger of the two specified Decimals.3.assertEquals(larger. Returns the hyperbolic cosine of d. max Integer i1 Integer i2 Integer Returns the larger of the two specified Integers.max(12.6). Returns the natural logarithm (base e) of the specified Decimal. Returns the hyperbolic cosine of d. max Long l1 Long l2 Long Returns the larger of the two specified Longs. Returns the trigonometric cosine of the angle specified by d. The hyperbolic cosine of d is defined to be (ex + e-x)/2 where e is Euler's number. 156.Reference Apex System Methods Name cos Arguments Decimal d Double d Decimal d Return Type Decimal Double Decimal Description Returns the trigonometric cosine of the angle specified by d. 156. Returns the logarithm (base 10) of the specified Double. For example: Decimal larger = math. cos cosh cosh Double d Double exp Decimal d Double d Decimal d Decimal Double Decimal exp floor floor Double d Double log Decimal d Double d Decimal d Double d Decimal d1 Decimal d2 Decimal Double Decimal Double Decimal log log10 log10 max max Double d1 Double d2 Double Returns the larger of the two specified Doubles. Returns the natural logarithm (base e) of the specified Double. For example: Integer remainder = math. If the result is less than -2. 156.assertEquals(smaller. mod Long L1 Long L2 Long Returns the remainder of L1 divided by L2. 0). and casting the result to type Integer. Returns the closest Integer to the specified Double by adding 1/2.647.0 and less than 1. min Long l1 Long l2 Long Returns the smaller of the two specified Longs.648 or greater than 2. Returns the value that is closest in value to d and is equal to a mathematical integer. min Integer i1 Integer i2 Integer Returns the smaller of the two specified Integers. Do not use. mod Integer i1 Integer i2 Integer Returns the remainder of i1 divided by i2.3). random Double Decimal d Double d Double d Decimal Double Integer rint rint round round Decimal d Integer 412 . 3).483. taking the floor of the result. 12.min(12.483. pow Double d Double exp Double Returns the value of the first Double raised to the power of exp.147. taking the floor of the result.assertEquals(remainder. This method is deprecated as of the Winter '08 Release. Returns the closest Integer to the specified Decimal by adding 1/2. Integer remainder2 = math. Apex generates an error.6).mod(8. For example: Decimal smaller = math.0. and casting the result to type Integer.147.3.Reference Apex System Methods Name min Arguments Decimal d1 Decimal d2 Return Type Decimal Description Returns the smaller of the two specified Decimals. system. system. min Double d1 Double d2 Double Returns the smaller of the two specified Doubles. Returns the value that is closest in value to d and is equal to a mathematical integer. use roundToLong or round(Decimal d). 2).mod(12. 2).assertEquals(remainder2. system. Instead. Returns a positive Double that is greater than or equal to 0. Returns the trigonometric tangent of the angle specified by d.0 if d is greater than 0. In other words. it is equivalent to sinh(x)/cosinh(x). Returns the hyperbolic sine of d.0 if d is less than 0.e-x)/(ex + e-x) where e is Euler's number.e-x)/(ex + e-x) where e is Euler's number. Returns the signum function of the specified Decimal. Returns the trigonometric tangent of the angle specified by d. The hyperbolic sine of d is defined to be (ex . Returns the hyperbolic sine of d. which is 0 if d is 0. Returns the correctly rounded positive square root of d. -1.0 if d is greater than 0. Returns the hyperbolic tangent of d. and casting the result to type Long.Reference Apex System Methods Name roundToLong Arguments Decimal d Return Type Long Description Returns the closest Long to the specified Decimal by adding 1/2. taking the floor of the result. 1. In other words. The hyperbolic tangent of d is defined to be (ex . taking the floor of the result.0 if d is less than 0. The absolute value of the exact tanh is always less than 1. The absolute value of the exact tanh is always less than 1. and casting the result to type Long. Returns the trigonometric sine of the angle specified by d.e-x)/2 where e is Euler's number. The hyperbolic tangent of d is defined to be (ex . roundToLong Double d Long signum Decimal d Decimal signum Double d Double sin Decimal d Double d Decimal d Double d Decimal d Double d Decimal d Double d Decimal d Decimal Double Decimal Double Decimal Double Decimal Double Decimal sin sinh sinh sqrt sqrt tan tan tanh tanh Double d Double 413 . The hyperbolic sine of d is defined to be (ex .e-x)/2 where e is Euler's number. -1. Returns the closest Long to the specified Double by adding 1/2. Returns the signum function of the specified Double. it is equivalent to sinh(x)/cosinh(x). which is 0 if d is 0. Returns the hyperbolic tangent of d. Returns the trigonometric sine of the angle specified by d. Returns the correctly rounded positive square root of d. 1. you first define your class with the @RestResource annotation to expose it as a REST resource. you add annotations to the class methods to expose them through REST. To expose your Apex class as a REST service. Represents an object used to pass data from an HTTP request to an Apex RESTful Web service method.RestRequest Description Contains the RestRequest and RestResponse objects. You can specify a resource for each endpoint. Sets the specified static resource corresponding to the endpoint. Represents an object used to pass data from an Apex RESTful Web service method to an HTTP response. Usage Use the methods in this class to set the response properties for testing HTTP callouts. Methods The following are instance methods of the MultiStaticResourceCalloutMock class. Method setHeader Arguments String headerName String headerValue Return Type Void Description Sets the specified header name and value for the fake response. See Testing HTTP Callouts Using MultiStaticResourceCalloutMock.Reference Apex System Methods MultiStaticResourceCalloutMock Methods Utility class used to specify a fake response using multiple resources for testing HTTP callouts. you can add the @HttpGet annotation to your method to expose it as a REST resource that can be called by an HTTP GET request. Class System.RestResponse 414 . For example. The static resource contains the response body. Sets the specified HTTP status for the response. setStaticResource String endpoint String resourceName Void setStatus setStatusCode String httpStatus Integer httpStatusCode Void Void See Also: StaticResourceCalloutMock Methods Apex REST Apex REST enables you to implement custom Web services in Apex and expose them through the REST architecture.RestContext System. System. Sets the specified HTTP status code for the response. Similarly. requestURI.RestContext class to access the RestRequest and RestResponse objects in your Apex REST methods. Usage Use the System. Account result = [SELECT Id. response System. Phone.requestURI. Methods The following are instance methods of the System. RestResponse res = RestContext. String accountId = req.lastIndexOf('/')+1). Returns the RestResponse for your Apex REST method.request. Name request Return Type System.RestResponse Sample The following example shows how to use RestContext to access the RestRequest and RestResponse objects in an Apex REST method. Properties The following are properties of the System.response. @RestResource(urlMapping='/MyRestContextExample/*') global with sharing class MyRestContextExample { @HttpGet global static Account doGet() { RestRequest req = RestContext.RestContext class.RestRequest class to pass request data into an Apex RESTful Web service method that is defined using one of the REST annotations. Name.Reference Apex System Methods RestContext Methods Contains the RestRequest and RestResponse objects.substring(req. } } See Also: Introduction to Apex REST RestRequest Methods Represents an object used to pass data from an HTTP request to an Apex RESTful Web service method. Usage Use the System. return result. Website FROM Account WHERE Id = :accountId].RestRequest class. 415 .RestRequest Description Returns the RestRequest for your Apex REST method. String> Returns the headers that are received by the request. an Apex exception will be thrown. Please note that the following headers aren't allowed: • • • • • cookie set-cookie set-cookie2 content-length authorization String name. The following methods are intended for unit testing Apex REST classes. You can modify them by calling the collection methods directly or you can use of the associated RestRequest methods shown in the previous table. You can use them to add header or parameter values to the RestRequest object without having to recreate the REST method call. String Blob Returns the IP address of the client making the request. Properties The following are properties of the System. Void String value If any of these are used. Method addHeader Arguments Return Type Description Adds a header to the request header map. then Apex REST copies the HTTP request body into the RestRequest.requestBody property. This method is intended for unit testing of Apex REST classes. addParameter String name. Note: While the RestRequest List and Map properties are read-only. Name headers httpMethod Return Type Description Map <String. This method is intended for unit testing of Apex REST classes. String> Returns the parameters that are received by the request.RestRequest class. you typically don't need to add a header or parameter to the RestRequest object because they are automatically deserialized into the corresponding properties. their contents are read-write. If there are parameters.Reference Apex System Methods Note: At runtime. Returns or sets the body of the request. then Apex REST attempts to deserialize the data 416 . String Returns one of the supported HTTP request methods: • DELETE • GET • HEAD • PATCH • POST • PUT params remoteAddress requestBody Map <String. If the Apex method has no parameters. Void String value Adds a parameter to the request params map . com/services/apexrest/Account/ then the requestURI is /services/apexrest/Account/.requestURI.website = website. resourcePath String Returns the REST resource path for the request. String website) { Account account = new Account(). DELETE. } @HttpGet global static Account doGet() { RestRequest req = RestContext. String phone.lastIndexOf('/')+1). return account. if the Apex REST class defines a urlMapping of /MyResource/*. Sample: An Apex Class with REST Annotated Methods The following example shows you how to implement the Apex REST API in Apex.request.substring(req. } } See Also: Introduction to Apex REST 417 . String accountId = req.substring(req. Website FROM Account WHERE Id = :accountId]. You can call these annotated methods from a client by issuing HTTP requests. String accountId = req. } @HttpPost global static String doPost(String name.lastIndexOf('/')+1). requestURI String Returns or sets everything after the host in the HTTP request string.salesforce. if the request string is https://instance.requestURI. Account account = [SELECT Id FROM Account WHERE Id = :accountId]. This class exposes three methods that each handle a different HTTP request: GET. Account result = [SELECT Id. For example.request. account. Name. @RestResource(urlMapping='/Account/*') global with sharing class MyRestResource { @HttpDelete global static void doDelete() { RestRequest req = RestContext. For example. insert account.response. Phone.phone = phone. RestResponse res = RestContext.Name = name.Id.requestURI. account. delete account.response. return result. and POST. RestResponse res = RestContext. the resourcePath property returns /services/apexrest/MyResource/*.Reference Apex System Methods Name Return Type Description into those parameters and the data won't be deserialized into the RestRequest.requestBody property.requestURI. account. their contents are read-write.Reference Apex System Methods RestResponse Methods Represents an object used to pass data from an Apex RESTful Web service method to an HTTP response. Usage Use the System. Method addHeader Arguments Return Type Description Adds a header to the response header map. then Apex REST serializes the return value as the response. Note: At runtime. Note: While the RestResponse List and Map properties are read-only. Void String value If any of these are used. you typically don't need to add a header to the RestResponse object because it's automatically deserialized into the corresponding properties. Methods The following are instance methods of the System. an Apex exception will be thrown. You can use them to add header or parameter values to the RestRequest object without having to recreate the REST method call. Properties The following are properties of the System.RestReponse class to pass response data from an Apex RESTful web service method that is defined using one of the REST annotations on page 132. Blob 418 . • If the method returns a value. The following methods are intended for unit testing Apex REST classes. Name headers responseBody Return Type Map <String. Please note that the following headers aren't allowed: • • • • • cookie set-cookie set-cookie2 content-length authorization String name. then Apex REST returns the response in the responseBody property. The response is either the serialized form of the method return value or it's the value of the responseBody property based on the following rules: • If the method returns void. Returns or sets the body of the response. String> Description Returns the headers to be sent to the response.RestResponse class. You can modify them by calling the collection methods directly or you can use of the associated RestResponse methods shown in the previous table.RestResponse class. The status code is returned by the RestResponse.statusCode property to a value that's not listed in the table.Reference Apex System Methods Name statusCode Return Type Integer Description Returns or sets the response status code. then an HTTP status of 500 is returned with the error message “Invalid status code for HTTP response: nnn” where nnn is the invalid status code value. Status Codes The following are valid response status codes. Note: If you set the RestResponse. Status Code 200 201 202 204 206 300 301 302 304 400 401 403 404 405 406 409 410 412 413 414 415 417 500 503 Description OK CREATED ACCEPTED NO_CONTENT PARTIAL_CONTENT MULTIPLE_CHOICES MOVED_PERMANENTLY FOUND NOT_MODIFIED BAD_REQUEST UNAUTHORIZED FORBIDDEN NOT_FOUND METHOD_NOT_ALLOWED NOT_ACCEPTABLE CONFLICT GONE PRECONDITION_FAILED REQUEST_ENTITY_TOO_LARGE REQUEST_URI_TOO_LARGE UNSUPPORTED_MEDIA_TYPE EXPECTATION_FAILED INTERNAL_SERVER_ERROR SERVER_UNAVAILABLE 419 . The supported status codes are listed in the following table and are a subset of the status codes defined in the HTTP spec.statusCode property. StaticResourceCalloutMock Methods Utility class used to specify a fake response for testing HTTP callouts. For more information. Name query Arguments String query Return Type sObject[sObject[]] Description Creates a dynamic SOSL query at runtime. Method setHeader Arguments String headerName String headerValue Return Type Void Description Sets the specified header name and value for the fake response. See Also: Introduction to Apex REST Search Methods The following are the system static methods for Search.Reference Apex System Methods Sample: An Apex Class with REST Annotated Methods See RestRequest Methods for an example of a RESTful Apex service class and methods. Usage Use the methods in this class to set the response properties for testing HTTP callouts. such as in regular assignment statements and for loops. which contains the response body. see Dynamic SOQL. Sets the specified static resource. setStaticResource setStatus setStatusCode String resourceName String httpStatus Integer httpStatusCode Void Void Void See Also: MultiStaticResourceCalloutMock Methods 420 . Sets the specified HTTP status for the response. Sets the specified HTTP status code for the response. See Testing HTTP Callouts Using StaticResourceCalloutMock. This method can be used wherever a static SOSL query can be used. Methods The following are instance methods of the StaticResourceCalloutMock class. are the same. If it is not. Name abortJob Arguments String Job_ID Return Type Void Description Stops the specified job. The x argument specifies the expected value. The stopped job is still visible in the job queue in the Salesforce user interface. Any data type opt_msg Void Asserts that the first two arguments. The returned error optionally contains the custom message specified in the last argument. a fatal error is returned that causes code execution to halt. set. • getJobId method—returns the AsyncApexJob object ID associated with the batch job as a string.executeBatch method—returns the AsyncApexJob object ID associated with the batch job as a string. You can’t catch an assertion failure using a try/catch block even though it is logged as an exception. assert Boolean condition. • Database. If they are not. Any data type y. or the special value null. The y argument specifies the actual value. a fatal error is returned that causes code execution to halt. map. The Job_ID is the ID associated with either AsyncApexJob or CronTrigger. x and y.schedule method—returns the CronTrigger object ID associated with the scheduled job as a string. • getTriggerId method—returns the CronTrigger object ID associated with the scheduled job as a string. The returned error optionally contains the custom message specified in the last argument. One of these IDs is returned by the following methods: • System. Note: AnyDataType represents any primitive. array. 421 . Asserts that condition is true.Reference Apex System Methods System Methods The following are the static methods for System. object record. Void Any data type opt_msg assertEquals Any data type x. the message of this debug statement will be written to the debug log. Note that when a map or set is printed. or any overridden toString method if the argument is a user-defined type. assertNotEquals Any data type x. currentPageReference System. x and y are different. If the log level for Apex Code is set to DEBUG or higher. Otherwise. The returned error optionally contains the custom message specified in the last argument. The DEBUG log level is used. Returns the current time in milliseconds. the output is sorted in key order and is surrounded with square brackets ([]). If the msg argument is not a string. This is used with Visualforce pages. Writes the msg argument. The String. When currentTimeMillis Long debug Any data type msg Void 422 . see PageReference Class on page 485. For more information. January 1. Any data type opt_msg Asserts that the first two arguments. You can’t catch an assertion failure using a try/catch block even though it is logged as an exception. in string format. If they are the same. to the execution debug log. Void Any data type y. if available. The y argument specifies the actual value. which is expressed as the difference between the current time and midnight. if no toString method is available.PageReference Returns a reference to the current page. a fatal error is returned that causes code execution to halt. The x argument specifies the expected value.Reference Apex System Methods Name Arguments Return Type Description You can’t catch an assertion failure using a try/catch block even though it is logged as an exception. 1970 UTC. it returns a string representation of the argument.valueOf to convert it into a string.valueOf method calls the toString method on the argument. the debug method calls String. the output is enclosed in parentheses (()). Note: Calls to System. to the execution debug log with the specified log level. if the lowest level. The String. if 423 . For example. see “Setting Debug Log Filters” in the Salesforce online help. The msg argument is the message or object to write in string format to the execution debug log. If the msg argument is not a string. For more information on log levels.debug are not counted as part of Apex code coverage. WARN.valueOf method calls the toString method on the argument. the debug log contains debug methods specified as either ERROR or WARN. is specified for Apex Code. Note: Calls to System. ERROR.valueOf to convert it into a string. is specified. Valid log levels are (listed from lowest to highest): • • • • • • • ERROR WARN INFO DEBUG FINE FINER FINEST Log levels are cumulative. debug Enum logLevel Any data type msg Void Writes the msg argument. The logLevel argument is the log level to set for this method. only debug methods with the log level of ERROR are logged. in string format.Reference Apex System Methods Name Arguments Return Type Description an array or list is printed.debug are not counted as part of Apex code coverage. the debug method calls String. If the next level. ApplicationReadWriteMode. it returns a string representation of the argument. false otherwise. false otherwise. For more information. Since a future method can't be invoked from another future method. Otherwise. see “Setting Debug Log Filters” in the Salesforce online help. false otherwise. or any overridden toString method if the argument is a user-defined type. Since a future method can't be invoked from a batch Apex job. now Datetime List<WorkItemIDs> List<Id> WorkItemIDs process String Action 424 . use this method to check if the currently executing code is a batch Apex job before you invoke a future method. use this method to check if the current code is executing within the context of a future method before you invoke a future method. This method returns the enum System. getApplication ReadWriteMode System.com upgrades and downtimes. Valid values are: • DEFAULT • READ_ONLY getApplicationReadWriteMode is available as part of 5 Minute Upgrade. if no toString method is available.Reference Apex System Methods Name Arguments Return Type Description available. isBatch Boolean Returns true if the currently executing code is invoked by a batch Apex job. Processes the list of work item IDs. see Apex Approval Processing Classes on page 539. isScheduled Boolean Returns true if the currently executing code is invoked by a scheduled Apex job. Returns the current date and time in the GMT time zone.ApplicationReadWriteMode Returns the read write mode set for an organization during Salesforce. For more information on log levels. isFuture Boolean Returns true if the currently executing code is invoked by code contained in a method annotated with future. This example shows how to delete all job records for jobs that have finished before today’s date. requestVersion System. System. you can determine the version of an installed instance of your package from which the calling code is referencing your package. Each execution of this method counts as a single row against the governor limit for DML statements. The requestVersion method isn’t supported for unmanaged packages.purgeOldAsyncJobs (Date.Reference Apex System Methods Name Arguments String Comments String NextApprover Return Type Description purgeOldAsyncJobs Date dt Integer Deletes asynchronous Apex job records (records in AsyncApexJob) for jobs that have finished execution before the specified date with a Completed. You can use this method to further reduce the size of AsyncApexJob by cleaning up more records. The dt argument specifies the date up to which old records are deleted. Using this method. Based on the version that the calling code has. If you 425 . and returns the number of records deleted. which is in the GMT time zone. Integer count = System.debug('Deleted ' + count + ' old jobs. The system cleans up asynchronous job records for jobs that have finished execution and are older than seven days. The date comparison is based on the CompletedDate field of AsyncApexJob. or Failed status.'). see Understanding Execution Governors and Limits.Version Returns a two-part version that contains the major and minor version numbers of a package. For more information. Aborted.today()). you can customize the behavior of your package code. and do not expose this functionality to end-users. runAs User user_var Void Changes the current user to the specified user. This method is used for testing your component behavior in different package versions that you upload to the AppExchange. resetPassword ID userID Boolean send_user_email System.Version version Void Changes the current package version to the package version specified in the argument. A package developer can use Version methods to continue to support existing behavior in classes and triggers in previous package versions while continuing to evolve the code. There is no limitation to the number of calls to this method in a transaction.Reference Apex System Methods Name Arguments Return Type Description call it from an unmanaged package. If you specify true for send_user_email. see Testing Behavior in Package Versions. Use setPassword if you don't want the user to be prompted to enter a new password when they log in. When the user logs in with the new password. Warning: Be careful with this method. and to select a security question and answer if they haven't already. the user is sent an email notifying them that their password was reset.ResetPasswordResult Resets the password for the specified user. You can only use runAs in a test method. Apex classes and triggers are saved with the version settings for each installed managed package that the class or trigger references. runAs System. they are prompted to enter a new password. All of the specified user's permissions 426 . an exception will be thrown. This method effectively sets a two-part version consisting of major and minor numbers in a test method so that you can test the behavior for different package versions. For sample usage of this method. A link to sign onto Salesforce using the new password is included in the email. You can create new users with runAs even if your organization has no additional user licenses. Note: Every call to runAs counts against the total number of DML statements issued in the process. and all cases where more than one record can be updated at a time. In this way. You can only use runAs in a test method. For more information. you bypass the mixed DML error that is otherwise returned when inserting or updating setup objects together with other sObjects. import wizards. Actual execution may be delayed based on service availability. In particular. Note: The runAs method ignores user license limits. schedule String JobName String CronExpression String Object schedulable_class Use schedule with an Apex class that implements the Schedulable interface to schedule the class to run at the time specified by CronExpression. but not inserted yet. Use extreme care if you are planning to schedule a class from a trigger. mass record changes through the user interface. 427 . You must be able to guarantee that the trigger will not add more scheduled classes than the 25 that are allowed.Reference Apex System Methods Name Arguments Return Type Description and record sharing are enforced during the execution of runAs. Note: Salesforce only adds the process to the queue at the scheduled time. See sObjects That Cannot Be Used Together in DML Operations. You can also use runAs to perform mixed DML operations in your test by enclosing the DML operations within the runAs block. consider API bulk updates. The runAs method implicitly inserts the user that is passed in as parameter if the user has been instantiated. see Using the runAs Method on page 150. 'MsgTxt'). Use the abortJob method to stop the job after it has been scheduled. In the following example. Warning: Be careful with this method.LoggingLevel level = LoggingLevel. they are not prompted to create a new password. System. WARN. the debug log contains debug methods specified as either ERROR or WARN. ERROR. is specified for Apex Code. For example.ERROR. If the next level. only debug methods with the log level of ERROR are logged.INFO. Using the System. and do not expose this functionality to end-users. When the user logs in with this password. today Date Returns the current date in the current user's time zone. is specified.Reference Apex System Methods Name Arguments Return Type Description For more information see. Use resetPassword if you want the user to go through the reset process and create their own password.debug(logginglevel. submit List<WorkItemIDs> List<ID> WorkItemIDs String Comments String NextApprover Submits the processed approvals. For more information. the string MsgTxt is not written to the debug log because the log level is ERROR and the debug method has a level of INFO: System. 428 . Valid log levels are (listed from lowest to highest): • • • • • • • ERROR WARN INFO DEBUG FINE FINER FINEST Log levels are cumulative. see Apex Approval Processing Classes on page 539. setPassword ID userID String password Void Sets the password for the specified user.Schedule Method on page 429. if the lowest level. System Logging Levels Use the loggingLevel enum to specify the logging level for all debug methods. The System. The System.getApplicationReadWriteMode().Schedule method uses the user's timezone for the basis of all schedules. and all cases where more than one record can be updated at a time. } else if (mode == ApplicationReadWriteMode.* ? / L W 429 .Schedule Method After you implement a class with the Schedulable interface. In particular.Schedule method to execute it. whether the user has permission to execute the class or not. .Schedule method takes three arguments: a name for the job.ApplicationReadWriteMode Enum Use the System. Actual execution may be delayed based on service availability.Reference Apex System Methods For more information on log levels. use the System.DEFAULT) { Account account = new Account(name = 'my account'). and the name of the class.READ_ONLY) { // Do nothing. insert account. This expression has the following syntax: Seconds Minutes Hours Day_of_month Month Day_of_week optional_year Note: Salesforce only adds the process to the queue at the scheduled time. The following are the values for the expression: Name Seconds Minutes Hours Day_of_month Values 0–59 0–59 0–23 1–31 Special Characters None None . consider API bulk updates.* / . an expression used to represent the time and date the job is scheduled to run. if (mode == ApplicationReadWriteMode. } } } Using the System. Note: Use extreme care if you are planning to schedule a class from a trigger. import wizards.ApplicationReadWriteMode enum returned by the getApplicationReadWriteMode to programmatically determine if the application is in read-only mode during Salesforce upgrades and downtimes. If DML operaton is attempted in readonly mode. Valid values for the enum are: • • DEFAULT READ_ONLY Example: public class myClass { public static void execute() { ApplicationReadWriteMode mode = System. see “Setting Debug Log Filters” in the Salesforce online help. mass record changes through the user interface. // InvalidReadOnlyUserDmlException will be thrown. You must be able to guarantee that the trigger will not add more scheduled classes than the 25 that are allowed. Using the System. The scheduler runs as system: all classes are executed. . if Month is specified as *.* / Day_of_week . APR to specify more than one month. Specifies the end of a range (last). For example. such as January 31. the Apex class runs every fifth day of the month. use JAN. the job is scheduled for every month. Specifies a range. . L always means the last day of the month. For example.* ? / L # optional_year . and the number after the slash is the interval amount. This is only available for Day_of_month and Day_of_week. if you specify 1/5 for Day_of_month. . When used with Day of month. For example. starting on the first of the month. Specifies increments. and so on. Specifies no specific value.* / The special characters are defined as follows: Special Character . For example. This is only available for Day_of_month and Day_of_week. February 28 for leap years.Reference Apex System Methods Name Month Values 1–12 or the following: • JAN • FEB • MAR • APR • MAY • JUN • JUL • AUG • SEP • OCT • NOV • DEC 1–7 or the following: • SUN • MON • TUE • WED • THU • FRI • SAT null or 1970–2099 Special Characters . use JAN-MAR to specify more than one month. The number before the slash specifies when the intervals will begin. . MAR. When * ? / L 430 . Description Delimits values. Specifies all values. and is generally used when specifying a value for one and not the other. If you specify 1W. The number after the # specifies the day of the month. This is only available for Day_of_week. which is the following Monday. it always means 7 or SAT. The following is the instance method for the System. Expression 0 0 13 * * ? 0 0 22 ? * 6L 0 0 10 ? * MON-FRI 0 0 20 * * ? 2010 Description Class runs every day at 1 PM. Do not use a range of values with L as the results might be unexpected. For example. specifying 2#2 means the class runs on the second Monday of every month. the class proschedule implements the Schedulable interface. you are specifying the last Monday of the month. if you specify 20W. it means the last of that type of day in the month.ResetPassword method that instantiated this 431 . The number before the # specifies weekday (SUN-SAT). the class does not run in the previous month. Class runs Monday through Friday at 10 AM. Tip: Use the L and W together to specify the last weekday of the month. In the following example. This can be used to access the generated password. For example. but on the third. Class runs the last Friday of every month at 10 PM. on the 13th of February. String sch = '0 0 8 13 2 ?'. For example. system. if you specify 2L. in the format weekday#day_of_month. When used with a Day_of_week value. W Specifies the nearest weekday (Monday-Friday) of the given day.ResetPasswordResult object: Method getPassword Arguments Returns String Description Returns the password generated as a result of the System. This is only available for Day_of_month.ResetPasswordResult object is returned by the System. Class runs every day at 8 PM during the year 2010. System.ResetPassword method. and the 20th is a Saturday.ResetPasswordResult Object A System. # Specifies the nth day of the month. The following are some examples of how to use the expression. the class runs on the 19th. proschedule p = new proschedule().schedule('One Time Pro'. The class is scheduled to run at 8 AM. p). sch. and the first is a Saturday.Reference Apex System Methods Special Character Description used with Day_of_week by itself. Reference Apex System Methods Method Arguments Returns Description System.csv file and for the specified sObject type. Name isRunningTest Arguments Return Type Description Boolean Returns true if the currently executing code was called by code contained in a method defined as testMethod. You must create the static resource prior to calling this method.ResetPasswordResult object. Use this method if you need to run different code depending on whether it was being called from a test.csv file. the static resource will be assigned a MIME type. see “Defining Static Resources” in the Salesforce online help. To learn more about static resources. and returns a list of the inserted sObjects. See Also: Batch Apex Future Annotation Apex Scheduler Test Methods The following are the system static methods for Test.csv extension. The static resource is a comma-delimited file ending with a . false otherwise.csv file containing the test records to load. The sObjectToken argument is the sObject type for which to insert test records. The file contains field names and values for the test records. The first line of the file must contain the field names and subsequent lines are the field values.SObjectType sObjectToken String resourceName List<sObject> Inserts test records from the specified static resource . Once you create a static resource for your . loadData Schema. Supported MIME types are: 432 . The name is case insensitive. The resourceName argument is the name of the static resource that corresponds to the . Reference Apex System Methods Name Arguments Return Type Description • • • • text/csv application/vnd. Note: If the code that performs the callout is in a managed package. see Adding SOSL Queries to Unit Tests on page 152.ms-excel application/octet-stream text/plain For an example. see Test. For examples. Defines a list of fixed search results to be returned by all subsequent SOSL statements in a test method.loadData Example. A Visualforce test method that sets the current PageReference for the controller. setCurrentPage PageReference page Void Void A Visualforce test method that sets the current PageReference for the controller. If opt_set_search_results is not specified.setMock from a test method in the same package with the same namespace to mock the callout. The application mode is reset 433 . The list of record IDs specified by opt_set_search_results replaces the results that would normally be returned by the SOSL queries if they were not subject to any WHERE or LIMIT clauses. setReadOnlyApplicationMode Boolean application_mode Void Sets the application mode for an organization to read-only in an Apex test to simulate read-only mode during Salesforce upgrades and downtimes. you must call Test. For more information. setCurrentPageReference PageReference page setFixedSearchResults ID[] Void opt_set_search_results setMock Type interfaceType Object instance Void Sets the response mock mode and instructs the Apex runtime to send a mock response whenever a callout is made through the HTTP classes or the auto-generated code from WSDLs. all subsequent SOSL queries return no results. see Testing HTTP Callouts and Testing Web Service Callouts. they are applied to the list of fixed search results. If these clauses exist in the SOSL queries. and so on. used for specifying a post install script in packages. All of the code before this method should be used to initialize variables. called in a startTest. All asynchronous calls made after the startTest method are collected by the system. Use this method in conjunction with the startTest method. When stopTest is executed. startTest Void Marks the point in your test code when your test actually begins. stopTest Void testInstall InstallHandler installImp Version ver Void Tests the implementation of the InstallHandler interface.Reference Apex System Methods Name Arguments Return Type Description to the default mode at the end of each Apex test run. Marks the point in your test code when your test ends. Each testMethod is allowed to call this method only once. Use this method when you are testing governor limits. do not count against your limits for the number of queued jobs. Note: Asynchronous calls. Any code that executes after the call to startTest and before stopTest is assigned a new set of governor limits. 434 . Tests will run as the test initiator in the development environment. such as @future or executeBatch. You can also use this method with stopTest to ensure that all asynchronous calls that come after the startTest method are run before doing any assertions or testing. setReadOnlyApplicationMode is available as part of 5 Minute Upgrade. Each testMethod is allowed to call this method only once. populate data structures. See also the getApplicationReadWriteMode System method. Any code that executes after the stopTest method is assigned the original limits that were in effect before startTest was called. all asynchronous processes are run synchronously. stopTest block. allowing you to set up everything you need to run your test. It then resets the application mode and performs a successful insert. } testUninstall UninstallHandleruninstImp Void Tests the implementation of the UninstallHandler interface. The isPush argument is optional and specifies if the upgrade is a push. 435 . Test. @isTest private class ApplicationReadOnlyModeTestClass { public static testmethod void test() { // Create a test account that is used for querying later. used for specifying an uninstall script in packages. Test. } setReadOnlyApplicationMode Example The following example sets the application mode to read only and attempts to insert a new account record. Tests will run as the test initiator in the development environment.testInstall(postinstall. which results in the exception. new Version(1. This method throws a run-time exception if the test uninstall fails. @isTest static void test() { UninstallClass uninstall = new UninstallClass().Reference Apex System Methods Name Arguments Boolean isPush Return Type Description The installImp argument is a class that implements the InstallHandler interface.testUninstall(uninstall). @isTest static void test() { PostInstallClass postinstall = new PostInstallClass(). The uninstImp argument is a class that implements the UninstallHandler interface. Account testAccount = new Account(Name = 'TestAccount'). The ver argument specifies the version number of the existing package installed in the subscriber organization.0)). This method throws a run-time exception if the test install fails. It’s default value is false. CA. Name FROM Account WHERE Name = 'TestAccount2']. Create a static resource for the .assertEquals(testAccount2. Click Save.BillingCity. d. // Set the application read only mode.READ_ONLY.CA.Reference Apex System Methods insert testAccount.setReadOnlyApplicationMode(false).BillingCountry sForceTest1. } } Test.csv file: a.com. insert testAccount2.assertEquals(false.sforcetest1. Account testAccount2 = new Account(Name = 'TestAccount2').San Francisco.The Landmark @ One Market. // Create a new account object.http://www. Should be successful.assertEquals(testAccount.94105.94105. Call Test.Website.http://www.csv file with three account records. insert testAccount2.San Francisco. b.http://www.(415) 901-7000. System. } catch (System.BillingStreet. Create a . testAccount2FromDb. System. and then New Static Resource.com.loadData to insert the test records. // Inserts should result in the InvalidReadOnlyUserDmlException // being thrown.The Landmark @ One Market Suite 300.Id.getApplicationReadWriteMode()). c. Name FROM Account WHERE Name = 'TestAccount'].CA. System. Choose the file you just created.San Francisco. testAccountFromDb.Id. Account testAccount2FromDb = [SELECT Id.US sForceTest3. Test.sforcetest2. // Verify that the application is in read-only mode. Name.csv file that has the data for the test records. 3. System.Phone. Name your static resource testAccounts.(415) 901-7000. Click Your Name > Setup > Develop > Static Resources. 1.loadData in a test method to populate the test accounts.csv file.csv file and a static resource. This is a sample .BillingPostalCode.US 2.InvalidReadOnlyUserDmlException e) { // Expected } // Insertion should work after read only application mode gets disabled. You can use this sample content to create your .setReadOnlyApplicationMode(true).BillingState.US sForceTest2. Test.Id). try { // Get the test account created earlier.1 Market St. and calling Test. @isTest private class DataUtil { 436 .94105.loadData Example The following are steps for creating a sample . true). System.com.sforcetest3.(415) 901-7000.Id). Account testAccountFromDb = [SELECT Id.assertEquals( ApplicationReadWriteMode. System. Contains methods for creating a new time zone and obtaining time zone properties.size() == 3). The time zone values you can use for the Id argument are any valid time zone values that the Java TimeZone class supports.sObjectType. tz.Name. The following are instance methods of the Timezone class.getTimeZone. 'testAccounts'). offset. String acctName = a1. such as the time zone ID.Reference Apex System Methods static testmethod void testLoadData() { // Load the test accounts from the static resource List<sObject> ls = Test.debug(acctName). such as the properties of the time zone returned by UserInfo. Example: TimeZone tz = TimeZone. Method getTimeZone Arguments String Id Return Type TimeZone Description Returns the time zone corresponding to the specified time zone ID.loadData(Account. // Perform some testing using the test records } } TimeZone Methods Represents a time zone.assertEquals( 'Pacific Standard Time'. System. Methods The following is the static method of the Timezone class. or the time zone returned by getTimeZone of this class. 437 . // Get first test account Account a1 = (Account)ls[0]. // Verify that all 3 test accounts were created System.getTimeZone( 'America/Los_Angeles').getDisplayName()). Usage You can use the methods in this class to get properties of a time zone.assert(ls. Returns this time zone’s ID. Method getDisplayName getID Arguments Return Type String String Description Returns this time zone’s display name. and display name. toString String Returns the string representation of this time zone. TimeZone tz = UserInfo.0.11. provide the methods’ implementation.getOffset(DateTime. This is an example output if the user’s time zone is America/Los_Angeles. // During daylight saving time for the America/Los_Angeles time zone System. use the newInstance method if you want to instantiate a Type that implements an interface and call its methods while letting someone else. // Not during daylight saving time for the America/Los_Angeles time zone System. System.newInstance(2012.debug('String format: ' + tz. The date argument is the date and time to evaluate.newInstance(2012. System.23.getOffset(DateTime. daylight saving time is -7 hours from GMT (-25200000 milliseconds) and standard time is -8 hours from GMT (-28800000 milliseconds).getID()). such as a subscriber of your package. Display name: Pacific Standard Time ID: America/Los_Angeles Offset: -25200000 Offset: -28800000 String format: America/Los_Angeles Type Methods Contains methods for getting the Apex type that corresponds to an Apex class and for instantiating new types.getTimeZone().23.debug('Offset: ' + tz.0))).Reference Apex System Methods Method getOffset Arguments Datetime date Return Type Integer Description Returns the time zone offset. System.debug('Offset: ' + tz. in milliseconds. Methods The following are static methods of the System.Type class. of the specified date to the GMT time zone.debug('ID: ' + tz. which can be a built-in or a user-defined class. Usage Use the forName methods to retrieve the type of an Apex class. Also. For this time zone. 438 .0))). The output of this sample varies based on the user's time zone. Note: The returned offset is adjusted for daylight saving time if the date argument falls within daylight saving time for this time zone.10.12.12.toString()).getDisplayName()). Sample This example shows how to get properties of the current user’s time zone and displays them to the debug log.0.debug('Display name: ' + tz. Type Returns the type that corresponds to the specified namespace and class name. For example. name) method and specify an empty string or null for the namespace argument. Type t = Type. The following are instance methods of the System. 'ClassName'). MyNamespace. Note: Use this method instead of forName(fullyQualifiedName) if it will be called from a managed package installed in an organization with no defined namespace. set the namespace argument to null or an empty string.forName('MyNamespace'. for example. the forName(fullyQualifiedName) method returns null. The namespace argument is the namespace of the class.. To get the name of a local type. set the namespace argument to an empty string or null. This example shows how to get the type that corresponds to the ClassName class and the MyNamespace namespace. 'ClassName'). The fullyQualifiedName argument is the fully qualified name of the class to get the type of.forName(''. use the forName(namespace. Note: When called from an installed managed package to get the name of a local type in an organization with no defined namespace.Type class. The name argument is the name of the class.Reference Apex System Methods Method forName Arguments String fullyQualifiedName Return Type System.ClassName. 439 . Type myType = Type. If the class doesn't have a namespace.Type Description Returns the type that corresponds to the specified fully qualified class name. Instead. The fully qualified class name contains the namespace name. forName String namespace String name System. debug use this method to convert their Type argument into a String. The newObj instance is declared with the interface type (Shape) that the ShapeImpl class implements. The return value of the newInstance method is cast to the Shape type. Shape newObj = (Shape)t. 440 . This method returns the same value as getName.toString(). The code in the package calls the subscriber's implementation of the interface methods by instantiating the subscriber’s Type. Because newInstance returns the generic object type.getName().valueOf and System.forName('MyClassName'). String. Type t = List<Integer>. typeName).assertEquals('MyClassName'. For example.class. String s = t. a package developer can provide an interface that a subscriber who installs the package can implement. It first gets a Type by calling forName with the name of a class (ShapeImpl). toString String Returns a string representation of the current type. Type t = Type.forName('ShapeImpl').Reference Apex System Methods Method getName Return Type String Description Returns the name of the current type. This example calls toString on the Type corresponding to a list of Integers. It first obtains a Type by calling forName. String typeName = t. then calls getName on the Type object. which is the type name. you should cast the return value to the type of the variable that will hold this value. Type t = Type. newInstance Object Creates an instance of the current type and returns this new instance. System. then calls newInstance on this Type object.newInstance(). This example shows how to get a Type’s name. This example shows how to create an instance of a Type. This method enables you to instantiate a Type that implements an interface and call its methods while letting someone else provide the methods’ implementation. it invokes the methods implemented in VehicleImpl. Vehicle v = (Vehicle)t. Sample: Instantiating a Type Based on Its Name The following sample shows how to use the Type methods to instantiate a Type based on its name. This is the Vehicle interface.Reference Apex System Methods Method Return Type Description System. global class VehicleImpl implements Vehicle { global Long getMaxSpeed() { return 100.newInstance(). } } 441 . global interface Vehicle { Long getMaxSpeed().className__c).assertEquals( 'LIST<Integer>'. In this sample.getInstance('Vehicle'). A typical application of this scenario is when a package subscriber provides a custom implementation of an interface that is part of an installed package. The last class contains the code sample that invokes the methods implemented in VehicleImpl. The package can get the name of the class that implements the interface through a custom setting in the subscriber’s org. This sample requires that you create a public list custom setting named CustomImplementation with a text field named className. } } The method in this class gets the name of the class that implements the Vehicle interface through a custom setting value.debug('Max speed: ' + v. // Get the Type corresponding to the class name Type t = Type. String getType().debug('Vehicle type: ' + v.forName(cs. } global String getType() { return 'Sedan'. // This class implements the Vehicle interface. Create one record for this custom setting with a data set name of Vehicle and a class name value of VehicleImpl. // Instantiate the type. It then instantiates this class by getting the corresponding type and calling the newInstance method.getMaxSpeed()). // Call the methods that have a custom implementation System.getType()). Vehicle represents the interface that the VehicleImpl class implements. Next. CustomImplementation__c cs = CustomImplementation__c. s). The package can then instantiate the type that corresponds to this class name and invoke the methods that the subscriber implemented. public class CustomerImplInvocationClass { public static void invokeCustomImpl() { // Get the class name from a custom setting. System. // The type of the instantiated object // is the interface. } This is the implementation of the Vehicle interface. debug(fullFileURL).Reference Apex System Methods Class Property The class property returns the System. Usage Use the methods of the System.getSalesforceBaseUrl(). The full URL is created by concatenating the Salesforce base URL with the record ID. or in Chatter posts.URL class. For example: System. For example. port. The following example creates a link to a Salesforce record. Account acct = [SELECT Id FROM Account WHERE Name = 'Acme' LIMIT 1].URL class to create links to objects in your organization. No arguments.id. Such objects can be files. sObject types.deserialize.class).URL class using the specified protocol. in activities. String protocol String host Integer port String file Description Creates a new instance of the System. ContentDocument doc = [SELECT Id FROM ContentDocument WHERE Title = 'myfile'].toExternalForm() + '/' + doc. host. It is exposed on all Apex built-in types including primitive data types and collections. Call this property on the type name.deserialize('100. or records that you want to include in external emails. This property can be used instead of forName methods. String fullFileURL = URL. and user-defined classes. logos. you can create a link to a file uploaded as an attachment to a Chatter post by concatenating the Salesforce base URL with the file ID. system. For example: Decimal n = (Decimal)JSON. and readValueAsStrict methods to get the type of the object to deserialize. images.Id. and file on the host. // Create a link to the file. URL Methods Represents a uniform resource locator (URL) and provides access to parts of the URL. as shown in the following example: // Get a file uploaded through Chatter.1'. deserializeStrict. Constructors Arguments Default constructor.toExternalForm() + '/' + acct.readValueAs.Type of the type it is called on.getSalesforceBaseUrl(). Decimal. 442 .Type t = Integer. JSONParser. Creates a new instance of the System.class. You can use this property for the second argument of JSON. Enables access to the Salesforce instance URL. String fullRecordURL = URL. URL class using the specified protocol.Reference Apex System Methods Arguments String protocol String host String file URL context String spec Description Creates a new instance of the System. Returns -1 if the URL scheme or the stream protocol handler for the URL doesn't define a default port number. String spec Creates a new instance of the System.URL.URL Returns the URL of the Salesforce instance. For example.lang.URL class by parsing the specified spec within the specified context.URL class using the specified string representation of the URL.net. java. Method getAuthority getDefaultPort Arguments Return String Integer Description Returns the authority portion of the current URL. getFile getHost getPath getPort getProtocol String String String Integer String Returns the file name of the current URL. Creates a new instance of the System. The following are instance methods for the System.com/apex/myVfPage.URL class. getSalesforceBaseUrl System.String) constructor for Java. and file on the host. Method getCurrentRequestUrl Returns System. Returns the protocol name of the current URL. 443 .salesforce.com.apexp.URL Description Returns the URL of an entire request on a Salesforce instance. For more information about the arguments of this constructor. The default port for the specified protocol is used.URL class. Methods The following are static methods for the System. https. For example. https://na1. see the corresponding URL(java.salesforce. Returns the default port number of the protocol associated with the current URL. Returns the path portion of the current URL. Returns the host name of the current URL. For example. host. Returns the port of the current URL. https://na1. toExternalForm(). For more information about the syntax of URIs and fragment components. // Get the base URL.getProtocol()). System. // Get the query string of the current request. sameFile System.debug('Current request URL: ' + currentRequestURL). // Create a new account called Acme that we will create a link for later. System. System.Reference Apex System Methods Method getQuery Arguments Return String Description Returns the query portion of the current URL. components of the base and full URL are obtained. getRef String Returns the anchor of the current URL.getSalesforceBaseUrl(). String sfdcBaseURL = URL. Returns null if no UserInfo portion exists. 444 . URL Sample In this example. returns false. This example prints out all the results to the debug log output.Id. Returns true if both URL objects reference the same remote resource.debug('Protocol: ' + URL.debug('Host: ' + URL.debug('URL of a particular account: ' + accountURL).getSalesforceBaseUrl(). // Get the URL for the current request. String accountURL = URL. insert myAccount. Account myAccount = new Account(Name='Acme'). String currentRequestURL = URL.debug('Query: ' + URL. see RFC3986. toExternalForm String Returns a string representation of the current URL. getUserInfo String Gets the UserInfo portion of the current URL.getSalesforceBaseUrl().getCurrentRequestUrl(). System.getSalesforceBaseUrl(). // Create the account URL from the base URL.toExternalForm() + '/' + myAccount. excluding the fragment component. // Get some parts of the base URL.toExternalForm(). System. Finally. otherwise.getCurrentRequestUrl(). Returns null if no query portion exists. a URL pointing to a specific account object is created.URL URLToCompare Boolean Compares the current URL with the specified URL object. Next.getHost()).debug('Base URL: ' + sfdcBaseURL ). the base URL and the full request URL of the current Salesforce server instance are retrieved.getQuery()). System. Returns null if no query portion exists. Batch Apex jobs.Reference Apex System Methods UserInfo Methods The following are the system static methods for UserInfo. getFirstName getLanguage getLastName getLocale String String String String Returns the context user's first name Returns the context user's language Returns the context user's last name Returns the context user's locale. getOrganizationId getOrganizationName getProfileId getSessionId String String String String 445 .assertEquals('en_US'. getName String Returns the context user's full name. The format is one of the following: • FirstName LastName • LastName. System.com API version 22. FirstName Returns the context organization's ID Returns the context organization's company name Returns the context user's profile ID Returns the session ID for the current session. such as @future methods. result). Name getDefaultCurrency Arguments Return Type String Description Returns the context user's default currency code for multiple currency organizations or the organization's currency code for single currency organizations. or scheduled Apex jobs. Note: For Apex saved using Salesforce. As a best practice. getDefaultCurrency returns null for single currency organizations.0 or earlier.getLocale(). The format of the name depends on the language preferences specified for the organization. For example: String result = UserInfo. ensure that your code handles both cases – when a session ID is or is not available. getSessionId returns null. For Apex code that is executed asynchronously. Valid values are: • • • • Theme1 Theme2 PortalDefault Webstore getUiThemeDisplayed String Returns the theme being displayed for the current user.getDisplayName()).getUserEmail(). getUserId getUserName getUserRoleId getUserType String String String String Returns the context user's ID Returns the context user's login name Returns the context user's role ID Returns the context user's type 446 . Example: String emailAddress = UserInfo.debug( 'Email address: ' + emailAddress).getTimeZone(). Valid values are: • • • • Theme1 Theme2 PortalDefault Webstore getUserEmail String Returns the current user’s email address.Reference Apex System Methods Name getTimeZone Arguments Return Type Description System. System. getUiTheme String Returns the default organization theme. Example: TimeZone tz = UserInfo. Use getUiThemeDisplayed to determine the theme actually displayed to the current user. System. System.getID()).debug( 'ID: ' + tz.TimeZone Returns the current user’s local time zone.debug( 'Display name: ' + tz. Otherwise. A called component can check the version against which the caller was compiled using the System.minorNumber. minor. The patchNumber is generated and updated only for a patch release. This allows you to continue to support existing behavior in classes and triggers in previous package versions while continuing to evolve the code.1.3). 447 . Since the System. The version number has the format majorNumber. Usage A package version is a number that identifies the set of components uploaded in a package. The major and minor numbers increase to a chosen value during every major release.Reference Apex System Methods Name Arguments Return Type Description Returns true if the context user has a license to the managed package denoted by namespace. A TypeException is thrown if namespace is an invalid parameter.requestVersion method doesn’t return a patch number. returns false. the patch number in the returned Version object is null. Methods The following are instance methods for the System. 2. The value returned by the System.requestVersion method and behave differently depending on the caller’s expectations.patchNumber (for example.Version class. Creates a three-part package version using the specified major. The System. and patch version numbers. isCurrentUserLicensed String namespace Boolean isMultiCurrencyOrganization Boolean Specifies whether the organization uses multiple currencies Version Methods Use the Version methods to get the version of a managed package of a subscriber and to compare package versions.requestVersion method is an instance of this class with a two-part version number containing a major and a minor number. Constructors Arguments Integer major Integer minor Integer major Integer minor Integer patch Description Creates a two-part package version using the specified major and minor version numbers.Version class can also hold also a three-part version number that includes a patch number. requestVersion().requestVersion(). Version Sample This example shows how to use the methods in this class.requestVersion() == new Version(1.compareTo(new Version(2.major() == 1) && (System.minor() > 0) && (System. to determine the managed package version of the code that is calling your package. Returns the minor package version of the calling code. if (System.requestVersion().minor() <=9)) { // Do something different for versions 1. along with the requestVersion method. System.0)) >= 0) { // Do something completely different for versions 2. Returns the patch package version of the calling code or null if there is no patch version.0 or greater } See Also: System Methods 448 .0)) { // Do something } if ((System.Version version Integer major minor patch Integer Integer Integer Returns the major package version of the of the calling code.Reference Apex System Methods Method compareTo Arguments Return Type Description Compares the current version with the specified version and returns one of the following values: • zero if the current package version is equal to the specified package version • an Integer value greater than zero if the current package version is greater than the specified package version • an Integer value less than zero if the current package version is less than the specified package version If a two-part version is being compared to a three-part version. the patch number is ignored and the comparison is based only on the major and minor numbers.1 to 1.requestVersion().9 } else if (System. such as attempting to access an index that is out of bounds. Any problem with data that does not exist. // Since s is null.Reference Using Exception Methods Using Exception Methods All exceptions support built-in methods for returning the error message and exception type. there are several different types of exceptions: Exception AsyncException Description Any problem with an asynchronous operation. and System. if iterator. For more JSONException Any problem with JSON serialization and deserialization operations. such as assigning a query that returns no records or more than one record to a singleton sObject variable. such as trying to access an sObject that has been deleted. System. For more information on Visualforce. such as trying to access an sObject that the current user does not have access to. A Chatter feature is required for code that has been deployed to an organization that does not have Chatter enabled. such as failing to enqueue an asynchronous call. see Apex Email Classes on page 452. RequiredFeatureMissing 449 .JSONGenerator. For more information. see the Visualforce Developer's Guide. Any problem with unauthorized access. For more information on Visualforce. see the Visualforce Developer's Guide. Used specifically by the Iterator next method. see the methods of System. such as failing to make a callout to an external system. information on Visualforce.JSONParser. Any problem with a mathematical operation. CalloutException DmlException EmailException InvalidParameterValueException Any problem with a URL. such as failure to deliver. Any problem with email. For example. This is generally used with Visualforce pages. such as dividing by zero. this exception is thrown. see the Visualforce Developer's Guide. s.JSON.next(). Any problem with a Web service operation. This is generally used with Visualforce pages.hasNext() == false and you call iterator. Any problem with dereferencing null. Any problem with a list. For more information. Any problem with a DML statement. In addition to the standard exception class. This exception is thrown if you try to access items beyond the end of the list. This is generally used with Visualforce pages. such as an insert statement missing a required field on a record. such as in the following code: String s. this call causes // a NullPointerException ListException MathException NoAccessException NoDataFoundException NoSuchElementException NullPointerException QueryException Any problem with SOQL queries.toLowerCase(). Any problem with the XmlStream classes. Returns the stack trace as a string. For more information on Visualforce. see XmlStream Classes. Returns the line number from where the exception was thrown. such as attempting to change a field in an update statement that can only be changed during insert. } } Common Exception Methods Exception methods are all called by and operate on a particular instance of an exception. The table below describes all instance exception methods. see the Visualforce Developer's Guide.getNumDml(). All types of exceptions have the following methods in common: Name getCause getLineNumber getMessage getStackTraceString getTypeName Arguments Return Type Exception Integer String String String Description Returns the cause of the exception as an exception object. For more information. Any problem with type conversions. For more information. i++) { // Process exception here System. For more information on Visualforce. Any problem with static methods in the Crypto utility class. This is generally used with Visualforce pages. Any problem with Strings.DmlException e) { for (Integer i = 0. Any problem with the serialization of data. when the searchString parameter contains less than two characters. Any problem with sObject records. Returns the error message that displays for the user. 450 . MathException. see the SOAP API Developer's Guide. such as DmlException.getDmlMessage(i)). such as failing to read or write XML. ListException. see the Visualforce Developer's Guide.debug(e. SecurityException SerializationException SObjectException StringException TypeException VisualforceException XmlException The following is an example using the DmlException exception: Account[] accts = new Account[]{new Account(billingcity = 'San Jose')}. such as attempting to convert the String 'a' to an Integer using the valueOf method. i < e. For more information. see Crypto Class on page 519. try { insert accts. and so on. Any problem with a Visualforce page. Returns the type of exception. for example.Reference Using Exception Methods Exception SearchException Description Any problem with SOSL queries executed with SOAP API search() call. such as a String that is exceeding your heap size. } catch (System. see Dynamic Apex. Returns the value of the System.REQUIRED_FIELD_MISSING.StatusCode Returns the ID of the failed record that caused the error described by the ith failed row. you can also use the system delivered classes for building your application. } getDmlId Integer i Integer i Integer i getDmlIndex getDmlMessage getDmlStatusCode Integer i getDmlType Integer i For more information about System. Deprecated. For more information on field tokens. ex. getDmlFieldNames Integer i getDmlFields Integer i Schema. if one has not already been set. getNumDml Integer Returns the number of failed rows for DML exceptions. DMLExceptions and EmailExceptions have the following additional methods: Name Arguments Return Type String [] Description Returns the names of the field or fields that caused the error described by the ith failed row.Reference Apex Classes Name initCause setMessage Arguments Return Type Description Sets the cause for the exception.StatusCode. Apex Classes Though you can create your classes using Apex. Use getDmlType instead.assertEquals( StatusCode. • Apex Email Classes 451 . For example: try { insert new Account(). sObject Exception Void String s Void DMLException and EmailException Methods In addition to the common exception methods. Returns the user message for the ith failed row. Returns the Apex failure code for the ith failed row.sObjectField Returns the field token or tokens for the field or fields [] that caused the error described by the ith failed row.DmlException ex) { System. String Integer String String System. Sets the error message that displays for the user.StatusCode enum. Returns the original row position of the ith failed row. } catch (System.getDmlType(0)). see Enums. The syntax is: Messaging. For more information.Interview Class Pattern and Matcher Classes HTTP (RESTful) Services Classes XML Classes Apex Approval Processing Classes BusinessHours Class Cases Class Apex Community Classes Knowledge Management Publishing Service Class Site Class Cookie Class Network Class Apex Email Classes Apex includes several classes and objects you can use to access Salesforce outbound and inbound email functionality. Note: Visualforce email templates cannot be used for mass email. use Salesforce email templates.SingleEmailMessage mail = new Messaging. and be in plain text or HTML format. and the total number of times it was opened. see “Tracking HTML Email” in the Salesforce online help. (For more information.Reference Apex Email Classes • • • • • • • • • • • • • • Exception Class Visualforce Classes Flow.SingleEmailMessage().) To send individual and mass email with Apex. You can use Salesforce to track the status of email in HTML format. see the following: • • Inbound Email Outbound Email Outbound Email You can use Apex to send individual and mass email. 452 . use the following classes: SingleEmailMessage Instantiates an email object used for sending a single email message. first opened and last opened. The email can include all standard email attributes (such as subject line and blind carbon copy address). including the date the email was sent. or those generated by Visualforce. Mass email messages sent with the sendEmail method count against the sending organization's daily mass email limit. instead of the logged-in user's Display Name. calls to the sendEmail method using SingleEmailMessage are rejected. The email address of the user calling the sendEmail method is inserted in the From Address field of the email header. single emails sent through the application are allowed. The sending email address in the header is also set to the field defined in OrgWideEmailAddress. The syntax is: Messaging. If setOrgWideEmailAddressId is passed a valid ID. which sends the email objects you instantiate with either the SingleEmailMessage or MassEmailMessage classes. Messaging Includes the static sendEmail method. When this limit is reached.MassEmailMessage.sendEmail(new Messaging. The syntax for sending an email is: Messaging. Use the Limits methods to verify the number of sendEmail methods in a transaction.Reference Apex Email Classes MassEmailMessage Instantiates an email object used for sending a mass email message. and the user receives a MASS_MAIL_LIMIT_EXCEEDED error code. Note the following: • • • • The email is not sent until the Apex transaction is committed.MassEmailMessage mail = new Messaging. It accepts an object ID to an OrgWideEmailAddress object. When this limit is reached. However. where Email is either Messaging.MassEmailMessage(). Any error returned in the SendEmailResult object indicates that no email was sent. 453 . and the user receives a SINGLE_EMAIL_LIMIT_EXCEEDED error code. where count indicates the total number of addresses that emails will be sent to.DisplayName field is used in the email header. Single email messages sent with the sendEmail method count against the sending organization's daily single email limit.Address. the OrgWideEmailAddress. opt_allOrNone). or whether it allows delivery of the messages that don't have errors (false). and Messaging.reserveMassEmailCapacity(count). bounced. calls to the sendEmail method using MassEmailMessage are rejected. • • Messaging. which can be called before sending any emails to ensure that the sending organization won't exceed its daily email limit when the transaction is committed and emails are sent. Includes the static reserveMassEmailCapacity and reserveSingleEmailCapacity methods.Email[] { mail } . All email that is returned. The default is true.SingleEmailMessage or Messaging. or received out-of-office replies goes to the user calling the method.reserveSingleEmailCapacity(count). The syntax is: Messaging. and returns a SendEmailResult object. Maximum of 10 sendEmail methods per transaction.SingleEmailMessage has a method called setOrgWideEmailAddressId. The optional opt_allOrNone parameter specifies whether sendEmail prevents delivery of all other messages when any of the messages fail due to an error (true). com email signature to the email.Id +' has been created. mail.setPlainTextBody('Your Case: ' + case. String[] toAddresses = new String[] {'user@acme. // Now create a new single email message object // that will send out a single email to the addresses in the To. the user receives a DUPLICATE_SENDER_DISPLAY_NAME error. mail.'). mail. String[] ccAddresses = new String[] {'smith@gmail. mail. // Optionally append the salesforce. // The email address of the user executing the Apex Code will be used.Reference Apex Email Classes Note: If both OrgWideEmailAddress.com').com'}.com'}.SingleEmailMessage().setUseSignature(false).setBccSender(false). mail.DisplayName and setSenderDisplayName are defined. // Specify the name used as the display name.setCcAddresses(ccAddresses).setSenderDisplayName('Salesforce Support').SingleEmailMessage[] { mail }).reserveSingleEmailCapacity(2).</a>'). Messaging. // Send the email you have created. // Set to True if you want to BCC yourself on the email. CC & BCC list. see Organization-Wide Addresses in the Salesforce online help.Id+'>click here.Id +' </b>has been created. see the following: • • • • • Base Email Methods SingleEmailMessage Methods MassEmailMessage Methods EmailFileAttachment Methods Messaging Methods 454 . Messaging. For more information. // Processes and actions involved in the Apex transaction occur next.setHtmlBody('Your case:<b> ' + case.salesforce. // Specify the subject line for your email address. Example // First.Id). mail.sendEmail(new Messaging. // Specify the text content of the email. mail. For more information. mail. mail. // Strings to hold the email addresses to which you are sending the email.<p>'+ 'To view your case <a href=https://na1. // Specify the address used when the recipients reply to the email. // Assign the addresses for the To and CC lists to the mail object.setToAddresses(toAddresses). reserve email capacity for the current Apex transaction to ensure // that we won't exceed our daily email limits when sending email after // the current transaction is committed.setSubject('New Case Created : ' + case.SingleEmailMessage mail = new Messaging.com/'+case.setReplyTo('support@acme. Messaging. // which conclude with sending a single email. the user cannot add BCC addresses on standard messages.SendEmailResult Object Methods SendEmailError Object Methods Base Email Methods The following table contains the email object methods used when sending both single and mass email. You must specify a value for setTemplateId. Note: If the BCC compliance option is set at the organization level. The ID of the template to be merged to create this email. Or. HTML.com representative for information on BCC compliance. If HTML email tracking is enabled for the organization.Reference Apex Email Classes • • Messaging. setTemplateID setSaveAsActivity Boolean Void Optional. all email content must be in plain text. you can define both setHtmlBody and setPlainTextBody. not to mass email methods. you will be able to track open rates. 455 . Note: setHtmlBody and setPlainTextBody apply only to single email methods.Visualforce email templates cannot be used for mass email. meaning the email is saved as an activity. Name setBccSender Argument Type Boolean Returns Void Description Indicates whether the email sender receives a copy of the email that is sent. For a mass mail. or both. setReplyTo String ID Void Void Optional. The default value is true. The following error code is returned: BCC_NOT_ALLOWED_IF_BCC_ COMPLIANCE_ENABLED. The email address that receives the message when a recipient replies. Note: If templates are not being used. setHtmlBody. or setPlainTextBody. This argument only applies if the recipient list is based on targetObjectId or targetObjectIds. Contact your salesforce. the sender is only copied on the first email sent. All email must have a recipient value of at least one of the following: • • • • toAddresses ccAddresses bccAddresses targetObjectId 456 . A list of blind carbon copy (BCC) addresses. setUseSignature Boolean Void SingleEmailMessage Methods The following table contains the email object methods used when sending a single email. These are in addition to the base email methods. targetObjectId.com representative for information on BCC compliance. Contact your salesforce. bccAddresses. The maximum allowed is 25. At least one value must be specified in one of the following fields: toAddresses. A list of carbon copy (CC) addresses. or targetObjectIds. The maximum allowed is 25. the user cannot add BCC addresses on standard messages. If the BCC compliance option is set at the organization level. The name that appears on the From line of the email. Indicates whether the email includes an email signature if the user has one configured. This cannot be set if the object associated with a setOrgWideEmailAddressId for a SingleEmailMessage has defined its DisplayName field.Reference Apex Email Classes Name setSenderDisplayName Argument Type String Returns Void Description Optional. This argument is allowed only when a template is not used. setCcAddresses String[] Void Optional. The default is true. The following error code is returned: BCC_NOT_ALLOWED_IF_BCC_ COMPLIANCE_ENABLED. meaning if the user has a signature it is included in the email unless you specify false. Name setBccAddresses Argument Type String[] Returns Void Description Optional. This argument is allowed only when a template is not used. ccAddresses. or setPlainTextBody. setHtmlBody. The email subject line. Or. Contains the parent emails' References and message IDs. specified by the sender. Optional. Contains the parent email or emails' message-IDs. Or. Optional. Optional. You must specify a value for setTemplateId. If this value is null. The In-Reply-To field of the outgoing email. The object's DisplayName field cannot be set if the setSenderDisplayName field is already set. setHtmlBody. You can attach multiple documents as long as the total size of all attachments does not exceed 10 MB. Optional. The HTML version of the email. The ID of the organization-wide email address associated with the outgoing email. Optional. You must specify a value for setTemplateId. and possibly the In-Reply-To fields. A list containing the file names of the binary and text files you want to attach to the email. the user's default value is used. The value is encoded according to the specification associated with the organization. Identifies the email or emails to which this one is a reply (parent emails).Reference Apex Email Classes Name Argument Type Returns Description • targetObjectIds setCharset String ID[] Void Void Optional. The References field of the outgoing email. you can define both setHtmlBody and setPlainTextBody. You can attach multiple files as long as the total size of all attachments does not exceed 10 MB. specified by the sender. A list containing the ID of each document object you want to attach to the email. Optional. you can define both setHtmlBody and setPlainTextBody. or setPlainTextBody. the subject line of the template overrides this value. The character set for the email. Optional. Optional. setDocumentAttachments setFileAttachments EmailFileAttachment[] Void setHtmlBody String Void setInReplyTo String Void setPlainTextBody String Void setOrgWideEmailAddressId ID Void setReferences String Void setSubject String Void 457 . The text version of the email. Identifies an email thread. If you are using an email template. Reference Apex Email Classes Name setTargetObjectId Argument Type ID Returns Void Description Required if using a template. If you specify a contact for the targetObjectId field. All email must have a recipient value of at least one of the following: • • • • • toAddresses ccAddresses bccAddresses targetObjectId targetObjectIds setWhatId ID Void Optional. The maximum number of email addresses allowed is 100. The value must be one of the following types: • Account • Asset • Campaign • Case • Contract • Opportunity • Order • Product • Solution 458 . All email must have a recipient value of at least one of the following: • • • • • toAddresses ccAddresses bccAddresses targetObjectId targetObjectIds setToAddresses String[] Void Optional. or user to which the email will be sent. optional otherwise. This helps to further ensure that merge fields in the template contain the correct data. The ID you specify sets the context and ensures that merge fields in the template contain the correct data. Do not specify the IDs of records that have the Email Opt Out option selected. A list of email address to which you are sending the email. lead. you can specify a whatId as well. This argument is allowed only when a template is not used. The ID of the contact. Reference Apex Email Classes Name Argument Type Returns Description • Custom MassEmailMessage Methods The following table contains the unique email object methods used when sending mass email. The objects must be of the same type (all contacts. If you specify a value for the targetObjectIds field. The IDs you specify set the context and ensure that merge fields in the template contain the correct data. or lead. Do not specify the IDs of records that have the Email Opt Out option selected. Name setDescription setTargetObjectIds Argument Type String ID[] Returns Void Void Description The description of the email. A list of IDs of the contacts. or all users). If you specify a list of contacts for the targetObjectIds field. You can list up to 250 IDs per email. The values must be one of the following types: • Contract • Case • Opportunity • Product 459 . This ensures that merge fields in the template contain the correct data. all leads. or users to which the email will be sent. you can specify a list of whatIds as well. All email must have a recipient value of at least one of the following: • • • • • toAddresses ccAddresses bccAddresses targetObjectId targetObjectIds setWhatIds ID[] Void Optional. leads. These are in addition to the base email methods. optionally specify a whatId as well to set the email context to a user. contact. This helps to further ensure that merge fields in the template contain the correct data. setHtmlBody. For a mass mail. In addition. specify one for each targetObjectId. you will be able to track open rates.com representative for information on BCC compliance. Name setBccSender Argument Type Boolean Returns Void Description Indicates whether the email sender receives a copy of the email that is sent. Note: If the BCC compliance option is set at the organization level. The email address that receives the message when a recipient replies.Reference Apex Email Classes Name Argument Type Returns Description Note: If you specify whatIds. The following error code is returned: BCC_NOT_ALLOWED_IF_BCC_ COMPLIANCE_ENABLED. setTemplateID setSaveAsActivity Boolean Void Optional. setReplyTo String ID Void Void Optional. the Messaging. The default value is true. If HTML email tracking is enabled for the organization. Contact your salesforce.MassEmailMessage class has access to the base email message methods. the user cannot add BCC addresses on standard messages. The ID of the template to be merged to create this email. Note: setHtmlBody and setPlainTextBody apply only to single email methods. not to mass email methods. Or. meaning the email is saved as an activity. the sender is only copied on the first email sent. you will receive an INVALID_ID_FIELD error. 460 . You must specify a value for setTemplateId. or setPlainTextBody. otherwise. you can define both setHtmlBody and setPlainTextBody. This argument only applies if the recipient list is based on targetObjectId or targetObjectIds. using this method results in the following error: System. inline content is displayed to the user when the message is opened. meaning if the user has a signature it is included in the email unless you specify false. Attachment content requires user action to be displayed. This cannot be set if the object associated with a setOrgWideEmailAddressId for a SingleEmailMessage has defined its DisplayName field. The default is true.LimitException: The daily limit for the org would be exceeded by this request.Reference Apex Email Classes Name setSenderDisplayName Argument Type String Returns Void Description Optional. This method can be called when you know in advance how many addresses emails will be sent to as a result of the transaction. If the transaction would cause the organization to exceed its daily email limit. setFileName setInline String file_name Boolean Content-Disposition Messaging Methods The following table contains the Messaging methods used when sending a single or mass email. Indicates whether the email includes an email signature if the user has one configured. Name Argument Type Returns Void Description Reserves email capacity to send mass email to the specified number of email addresses. as opposed to existing documents in Salesforce. reserveMass Integer EmailCapacity AmountReserved 461 . The name of the file to attach. setUseSignature Boolean Void EmailFileAttachment Methods The EmailFileAttachment object is used in the SingleEmailMessage object to specify attachments passed in as part of the request. The name that appears on the From line of the email. In most cases. Name setBody setContentType Argument Type Blob attachment String content_type Returns Void Void Void Void Description The attachment itself. The attachment's Content-Type. Specifies a Content-Disposition of inline (true) or attachment (false). after the current transaction commits. SendEmailResult[] Sends the list of email objects instantiated with either SingleEmailMessage or MassEmailMessage and returns a list of SendEmailResult objects. e.parentid = c. The optional opt_allOrNone parameter specifies whether sendEmail prevents delivery of all other messages when any of the messages fail due to an error (true). using this method results in the following error: System. // Set to draft status.LimitException: The daily limit for the org would be exceeded by this request. Before running this example. The default is true. make sure to replace the email address with a valid address.TextBody = 'Sample email message.id. This optional parameter specifies whether sendEmailMessage prevents delivery of all other messages when any of the messages fail due to an error (true). EmailMessage e = new EmailMessage(). reserveSingle Integer EmailCapacity AmountReserved sendEmail Messaging. e. or whether it allows delivery of the messages that don't have errors (false). e. This method can be called when you know in advance how many addresses emails will be sent to as a result of the transaction. insert c.Reference Apex Email Classes Name Argument Type Returns Void Description Reserves email capacity to send single email to the specified number of email addresses. // This status is required // for sendEmailMessage().If the transaction would cause the organization to exceed its daily email limit. The sendEmailMessage method assumes that the optional opt_allOrNone parameter is always false and ignores the value you set.Email[] Boolean allOrNothing Messaging. 462 . the example sends a draft email message and checks the results.'. after the current transaction commits. Example: This example shows how to send a draft email message.SendEmailResult[] Sends up to 10 draft email messages as defined by the specified email message IDs and returns a list of SendEmailResult objects. Next.Status = '5'. It creates a case and a new email message associated with the case. sendEmailMessage List <ID> emailMessageIds Boolean allOrNothing Messaging. or whether it allows delivery of the messages that don't have errors (false). Case c = new Case(). which has the following methods.assertEquals(1.SendEmailResult Object Methods The sendEmail method returns a list of SendEmailResult objects.Reference Apex Email Classes Name Argument Type Returns Description e.Subject = 'Apex sample'. as there could have been a problem with the email address or it could have bounced or been blocked by a spam blocker. System. e. getTargetObjectId String 463 . List<Messaging. results. insert e. The text of the error message. The full list of status codes is available in the WSDL file for your organization.SendEmailResult> results = Messaging. Identifies which fields in the object. Even if isSuccess is true.size()). Name getErrors Returns Description SendEmailError[] If an error occurred during the sendEmail method.StatusCode A code that characterizes the error. The ID of the target record for which the error occurred. Messaging. results[0].success). Name getFields Returns String[] String Description A list of one or more field names. a SendEmailError object is returned.sendEmailMessage(new ID[] { e.com'.assertEquals(true. For more information about accessing the WSDL file for your organization. These methods take no arguments. isSuccess SendEmailError Object Methods The SendEmailResult object may contain a SendEmailError object. These methods take no arguments. System. Boolean Indicates whether the email was successfully submitted for delivery (true) or not (false). affected the error condition. see “Downloading Salesforce WSDLs and Client Authentication Certificates” in the Salesforce online help.ToAddress = 'customer@email. if any. Each SendEmailResult object has the following methods.id }). it does not mean the intended recipients received the email. getMessage getStatusCode System. and view or specify addresses for that email service. This section contains information about the following: • • • • • • • • What is the Apex Email Service? Using the InboundEmail Object InboundEmail Object InboundEmail. Enterprise and Unlimited Edition organizations. activate or deactivate it. click Your Name > Setup > Develop > Email Services. Note: Before deleting email services. Note: The Apex email service is only available in Developer. and attachments of inbound email. To give multiple users access to a single email service. Click Delete to delete an email service. and processed by Apex classes that utilize the InboundEmail object. Salesforce limits the total number of messages that all email services combined. To use email services. discarded.BinaryAttachment Object InboundEmail. you can create an email service that automatically creates contact records based on contact information in messages. You can associate each email service with one or more Salesforce-generated email addresses to which users can send messages for processing. or queued for processing the next day. Messages that exceed this limit are bounced. When defining email services. For example. including On-Demand Email-to-Case. you must delete all associated email service addresses. Associate a single Salesforce-generated email address with the email service. headers. Click Edit to make changes to an existing email service. For example. Select an existing email service to view its configuration. can process daily. Salesforce calculates the limit by multiplying the 464 . • • • • Click New Email Service to define a new email service. and write an Apex class that executes according to the user accessing the email service.Reference Apex Email Classes Inbound Email You can use Apex to receive and process email and attachments.TextAttachment Object InboundEmailResult Object InboundEnvelope Object What is the Apex Email Service? Email services are automated processes that use Apex classes to process the contents. note the following: • • An email service only processes messages it receives at one of its addresses. depending on how you configure the failure response settings for each email service. you can: • • Associate multiple Salesforce-generated email addresses with the email service and allocate those addresses to users. The email is received by the Apex email service.Header Object InboundEmail. you can write an Apex class that identifies the user based on the user's email address and creates records on behalf of that user. as well as perform many functions. You can use Apex classes that implement the Messaging.InboundEmailResult result = new Messaging.InboundEmailHandler { global Messaging. and attachments of inbound email messages. if you have ten licenses. your organization can process up to 10. body HTML and attachments) exceeds approximately 10 MB (varies depending on language and character set).InboundEmailHandler interface to handle an inbound email message.Reference Apex Email Classes • • • number of user licenses by 1. global class CreateTaskEmailExample implements Messaging. Name. // Try to look up any contacts based on the email from address // If there is more than one contact with the same email address. up to a daily maximum of 1.000. For example. Salesforce creates a separate InboundEmail object that contains the contents and attachments of that email. For each email service.fromAddress LIMIT 1].add(new Task(Description = myPlainText. Priority = 'Normal'. try { Contact vCon = [SELECT Id. String myPlainText= ''. } // If an exception occurs when the query accesses 465 .InboundEmailResult().plainTextBody.InboundEnvelope env){ // Create an InboundEmailResult object for returning the result of the // Apex Email Service Messaging. // Insert the new Task insert newTask.InboundEmailResult handleInboundEmail(Messaging.subject.Id)). Email FROM Contact WHERE Email = :email. // an exception will be thrown and the catch statement will be called. you can access an InboundEmail object to retrieve the contents. IsReminderSet = true.now()+1. Email services rejects email messages and notifies the sender if the email (combined body text. Example 1: Create Tasks for Contacts The following is an example of how you can look up a contact based on the inbound email address and create a new task. newTask.000.000 email messages a day. Using the InboundEmail Object For every email the Apex email service domain receives.inboundEmail email. System. headers. // New Task object to be created Task[] newTask = new Task[0]. ReminderDateTime = System. // Add a new Task to the contact record we just found above. Subject = email. Messaging. WhoId = vCon. // Add the email plain text into the local variable myPlainText = email. Using the handleInboundEmail method in that class.debug('New Task Object: ' + newTask ).000. you can tell Salesforce to send error email messages to a specified address instead of the sender's email address. Status = 'Inbound Email'. Email service addresses that you create in your sandbox cannot be copied to your production organization. a QueryException is called. if any. audio. including: • Recieved from • Custom headers • Message-ID • Date The HTML version of the email. // The exception is written to the Apex debug log. The name that appears in the From field. Indicates whether the HTML body text is truncated (true) or not (false. The email address that appears in the From field. Contains the parent email or emails' message-IDs.BinaryAttachment[] A list of binary attachments received with the email.success = true. if specified by the sender. if any. application. The Message-ID—the incoming email's unique identifier. Identifies the email or emails to which this one is a reply (parent emails). } // Set the result to true.) The In-Reply-To field of the incoming email. The plain text version of the email. // Return the result for the Apex Email Service return result. catch (QueryException e) { System.Reference Apex Email Classes // the contact record. Name binaryAttachments Type Description InboundEmail. ccAddresses fromAddress fromName headers String[] String String InboundEmail. No need to send an email back to the user // with an error message result. } } InboundEmail Object An InboundEmail object has the following fields. if specified by the sender. Examples of binary attachments include image.Header[] A list of carbon copy (CC) addresses. and video files.debug('Query Issue: ' + e). if any. A list of the RFC 2822 headers in the email. htmlBody String Boolean String htmlBodyIsTruncated inReplyTo messageId String String plainTextBody 466 . respectively. The email address that appears in the reply-to header. such as Date or Message-ID. and possibly the In-Reply-To fields.TextAttachment[] The subject line of the email.BinaryAttachment object. 467 .) The References field of the incoming email. If there is no reply-to header. this field is identical to the fromAddress field. A list of text attachments received with the email.Reference Apex Email Classes Name Type Description Indicates whether the plain body text is truncated (true) or not (false. toAddresses String[] The email address that appears in the To field. These are saved as text/x-vcard and text/calendar MIME types. and video files.vcs extension. InboundEmail.BinaryAttachment Object An InboundEmail object stores binary attachments in an InboundEmail. An InboundEmail. if any. InboundEmail.BinaryAttachment object has the following fields. application. Identifies an email thread. The text attachments can be any of the following: • • Attachments with a Multipurpose Internet Mail Extension (MIME) type of text Attachments with a MIME type of application/octet-stream and a file name that ends with either a .vcf or . The value of the header. if any. audio.Header object with the following fields. Name name value Type String String Description The name of the header parameter. Examples of binary attachments include image. Contains a list of the parent emails' References and message IDs.Header Object An InboundEmail object stores RFC 2822 email header information in an InboundEmail. plainTextBodyIsTruncated Boolean references String [] replyTo String subject textAttachments String InboundEmail. The primary and sub MIME-type. If false. Salesforce rejects the inbound email and sends a reply email to the original sender containing the message specified in the Message field. Name body bodyIsTruncated Type String Boolean String String String Description The body of the attachment.TextAttachment Object An InboundEmail object stores text attachments in an InboundEmail. The name of the attached file.) The original character set of the body field. If this object is null. 468 . Indicates whether the attachment body text is truncated (true) or not (false. InboundEnvelope Object The InboundEnvelope object stores the envelope information associated with the inbound email. The InboundEmailResult object has the following fields.TextAttachment object has the following fields. These are saved as text/x-vcard and text/calendar MIME types. respectively.vcs extension. and has the following fields. The primary and sub MIME-type. InboundEmail.Reference Apex Email Classes Name body fileName mimeTypeSubType Type Blob String String Description The body of the attachment. the result is assumed to be successful. The name of the attached file. charset fileName mimeTypeSubType InboundEmailResult Object The InboundEmailResult object is used to return the result of the email service. The body is re-encoded as UTF-8 as input to the Apex method. An InboundEmail.TextAttachment object. message String A message that Salesforce returns in the body of a reply email. Name success Type Boolean Description A value that indicates whether the email was successfully processed. The text attachments can be any of the following: • • Attachments with a Multipurpose Internet Mail Extension (MIME) type of text Attachments with a MIME type of application/octet-stream and a file name that ends with either a . This field can be populated with text irrespective of the value returned by the Success field.vcf or . that is. and can be thrown and caught as expected. // Your code here if (i < 5) throw new MyException(). Exceptions can be top-level classes. For example. if any. the following code defines an exception type within an anonymous block: public class MyException extends Exception {} try { Integer i. such as “MyException”. Constructing an Exception You can construct exceptions: 469 . “PurchaseException” and so on.Reference Exception Class Name toAddress fromAddress Type String String Description The name that appears in the To field of the envelope. they can implement interfaces. User-defined exception class names must end with the string exception. } catch (MyException e) { // Your MyException handling code here } Like Java classes. The name that appears in the From field of the envelope. and catch blocks can catch any portion. Exceptions that you create behave as any other standard exception type. All exception classes automatically extend the system-defined base class exception. For example: public class BaseException extends Exception {} public class OtherException extends BaseException {} try { Integer i. they can have member variables. Exception Class You can create your own exception classes in Apex. // Your code here if (i < 5) throw new OtherException('This is bad'). } catch (BaseException e) { // This catches the OtherException } This section contains the following topics: • • Constructing an Exception Using Exception Variables See also Using Exception Methods. if any. user-defined exception types can form an inheritance tree. and so on. methods and constructors. • With a single String argument that specifies the error message: new MyException('This is bad'). • With both a String error message and a chained exception cause that displays in any stack trace: new MyException('This is bad'. e). } The following figure shows the stack trace that results from running the code above: Figure 9: Stack Trace For Exceptions (From Debug Log) 470 .Reference Exception Class • With no arguments: new MyException(). • With a single Exception argument that specifies the cause and that displays in any stack trace: new MyException(e). e). For example the following code generates a stack trace with information about both My1Exception and My2Exception: public class My1Exception extends Exception {} public class My2Exception extends Exception {} try { throw new My1Exception(). } catch (My1Exception e) { throw new My2Exception('This is bad'. s.Action object that uses the save action: ApexPages. the standard controller executes in user mode. arguments. and return types can be declared of type Exception. For example: Exception e1.Reference Visualforce Classes Using Exception Variables As in Java. extending a standard controller allows you to build a Visualforce page that respects user permissions. Instantiation The following code snippet illustrates how to instantiate a new ApexPages. in which the object and field-level permissions of the current user are ignored. but you must also reimplement any functionality that was already provided in a standard controller. For more information. you can define new navigation elements or behaviors. Like other Apex classes.Action to create an action method that you can use in a Visualforce custom controller or controller extension. try { String s = null.tolowercase(). Extensions allow you to leverage the functionality of another controller while adding your own custom logic. the transient keyword can be used when declaring methods in controllers and controller extensions. custom controllers execute entirely in system mode. you can specify whether a user can execute methods in a controller extension based on the user's profile. For example. Apex can also be used to provide custom logic for Visualforce pages through custom Visualforce controllers and controller extensions: • A custom controller is a class written in Apex that implements all of a page's logic. Although the extension class executes in system mode. // . Action Class You can use ApexPages.. You can specify whether a user can execute methods in a custom controller based on the user's profile. } catch (System. field-level security. see the Visualforce Developer's Guide. you could create a saveOver method on a controller extension that performs a custom save. 471 . or passed // into or out of another method } Visualforce Classes In addition to giving developers the ability to add business logic to Salesforce system events such as button clicks and related record updates. This section includes information about the system-supplied Apex classes that can be used when building custom Visualforce controllers and controller extensions. variables.. and sharing rules of the current user are enforced. In addition to these classes. If you use a custom controller. For more information on Visualforce.which can be assigned to a variable. As with custom controllers. // This will generate a null pointer exception.NullPointerException e) { e1 = e. which is a system-defined based class in Apex.Action('{!save}'). see Using the transient Keyword on page 123. Because standard controllers execute in user mode..Action saveAction = new ApexPages.. in which the permissions. • A controller extension is a class written in Apex that adds to or overrides behavior in a standard or custom controller. without leveraging a standard controller. PageReference Invokes the action. <apex:commandButton value="Perform Controller Action" action="{!actionToInvoke}"/> </apex:component> <apex:page controller="pageCon"> ...Apex.. This example extends the standard controller for Account.PageBlock().Apex.. /> .. public class pageCon{ public PageReference RedirectToStep2(){ // ..Action" . the system writes a message to the system debug log. The following is the controller extension.Step2. in addition to the account being updated or created. System.. return Page. <apex:component> <apex:attribute name="actionToInvoke" type="ApexPages. Example In the following example.PageBlock pageBlk = new Component. see “Viewing Debug Logs” in the Salesforce online help.Component> Description Returns a reference to the child components for the component.. when the user updates or creates a new Account and clicks the Save button. The table below describes the instance methods for Action. Dynamic Component Methods and Properties All dynamic Visualforce components represented in Apex have access to the following properties. Name getExpression invoke Arguments Return Type String Description Returns the expression that is evaluated when the action is invoked.. For example: Component. Properties Name childComponents Data Type List <ApexPages.Reference Visualforce Classes Methods The action methods are all called by and operate on a particular instance of Action. } } The following is the Visualforce markup for a page that uses the above controller extension. 472 .. <c:myComp actionToInvoke="{!RedirectToStep2}"/> </apex:page> For information on the debug log. // . facets String Sets the content of a facet to a dynamic component. 473 .Apex.DataTable(). IdeaStandardController Class IdeaStandardController objects offer Ideas-specific functionality in addition to what is provided by the StandardController Class.PageBlockSection pageBlkSection = new Component. An instance can be obtained through a constructor of a custom extension controller when using the standard ideas controller.Apex.Apex.OutputText(value='Footer Copyright').InputField(). inpField. For information on enabling these classes for your organization.name_of_facet. Note: This property is only accessible by components that support facets.Reference Visualforce Classes Name Data Type Description Component. ApexPages.Apex.id = '{!$User.childComponents. expressions String Sets the content of an attribute using the expression language notation. inpField.expressions. For example: Component. The notation for this is facet. The notation for this is expressions.value = '{!Account.Name}'.InputField inpFld = new Component.expressions. Note: The IdeaStandardSetController and IdeaStandardController classes are currently available through a limited release program.facets.PageBlockSection(title='dummy header').Component. contact your salesforce. pageBlk.OutputText footer = new Component.com representative.footer = footer.add(pageBlkSection).FirstName}'.Apex. Instantiation An IdeaStandardController object cannot be instantiated.name_of_attribute.Apex. For example: Component.Apex.DataTable myDT = new Component. myDT. such as foo__r.Reference Visualforce Classes Methods A method in the IdeaStandardController object is called by and operated on a particular instance of an IdeaStandardController. This method adds a reference to each field specified in fieldNames so that the controller can explicitly access those fields as well.PageReference Returns the PageReference of the cancel page. System. This method returns the following comment properties: • id • commentBody • createdDate • createdBy. or they can be explicit relationships to fields. you must use the reset() method before calling addFields(). The table below describes the instance method for IdeaStandardController. cancel delete edit getId System. System. the IdeaStandardController class inherits all the methods associated with the StandardController Class. This method should be called before a record has been loaded—typically. such as AccountId. 474 . If this method is called outside of the constructor. Name addFields Arguments List<String> fieldNames Return Type Void Description When a Visualforce page is loaded. Name getCommentList Arguments Return Type IdeaComment[] Description Returns the list of read-only comments from the current page. String Returns the ID of the record that is currently in context.PageReference Returns the PageReference of the standard edit page.communityNickname In addition to the method listed above. The following table lists these methods.Id • createdBy. based on the value of the id query string parameter in the Visualforce page URL. the fields accessible to the page are based on the fields referenced in the Visualforce markup. This method is only for controllers used by dynamicVisualforce bindings. The strings in fieldNames can either be the API name of a field. it's called by the controller's constructor.PageReference Deletes record and returns the PageReference of the delete page.myField__c. For example: <apex:outputText value="{!account.IdeaStandardController)controller. public class MyIdeaExtension { private final ApexPages. must be queried using a SOQL expression. All other fields.PageReference Returns the PageReference object of the standard detail page. including fields from any related objects. This method is only for controllers used by dynamicVisualforce bindings. and it must be called directly before addFields. Hide the component from display by setting the component's rendered attribute to false.PageReference Saves changes and returns the updated PageReference.billingcity} {!account.Reference Visualforce Classes Name getRecord Arguments Return Type SObject Description Returns the record that is currently in context. This example provides the framework for manipulating the comment list data before displaying it on a Visualforce page. Note that only the fields that are referenced in the associated Visualforce markup are available for querying on this SObject. } public List<IdeaComment> getModifiedComments() { IdeaComment[] comments = ideaController. System. Any changes made to the record prior to this method call are discarded. Example The following example shows how an IdeaStandardController object can be used in the constructor for a custom list controller.contacts}" rendered="false"/> reset Void Forces the controller to reacquire access to newly referenced fields. This method is only used if addFields is called outside the constructor. // modify comments here 475 . save view System. based on the value of the id query string parameter in the Visualforce page URL. public MyIdeaExtension(ApexPages.IdeaStandardController controller) { ideaController = (ApexPages.getCommentList(). Tip: You can work around this restriction by including a hidden component that references any additional fields that you want to query.IdeaStandardController ideaController. The table below describes the instance method for IdeaStandardSetController. Methods A method in the IdeaStandardSetController object is called by and operated on a particular instance of an IdeaStandardSetController. For information on enabling these classes for your organization.id}">{!idea. <!-.id}" pageOffset="-1">Prev</ideas:detailOutputLink> | <ideas:detailOutputLink page="detailPage" ideaId="{!idea. in the following example you need to specify the ID of a specific idea (for example. contact your salesforce. /apex/detailPage?id=<ideaID>) whose comments you want to view.commentBody} </apex:dataList> <ideas:detailOutputLink page="detailPage" ideaId="{!idea. } } The following Visualforce markup shows how the IdeaStandardController example shown above can be used in a page.Reference Visualforce Classes return comments. 476 . Note: For the Visualforce page to display the idea and its comments.title} </ideas:detailOutputLink> <br/><br/> <apex:outputText >{!idea. Note: The IdeaStandardSetController and IdeaStandardController classes are currently available through a limited release program. This page must be named detailPage for this example to work. An instance can be obtained through a constructor of a custom extension controller when using the standard list controller for ideas.body}</apex:outputText> </apex:pageBlock> <apex:pageBlock title="Comments Section"> <apex:dataList var="a" value="{!modifiedComments}" id="list"> {!a.com representative.page named detailPage --> <apex:page standardController="Idea" extensions="MyIdeaExtension"> <apex:pageBlock title="Idea Section"> <ideas:detailOutputLink page="detailPage" ideaId="{!idea.id}" pageOffset="1">Next</ideas:detailOutputLink> </apex:pageBlock> </apex:page> See Also: Ideas Class IdeaStandardSetController Class IdeaStandardSetController objects offer Ideas-specific functionality in additional to what is provided by the StandardSetController Class. Instantiation An IdeaStandardSetController object cannot be instantiated. The following is a list of properties returned by this method: • Body • Categories • Category • CreatedBy.CommentBody • LastComment.PageReference Returns the PageReference of the original page. getFilterId getHasNext String Boolean 477 . the IdeaStandardSetController class inherits the methods associated with the StandardSetController Class. The maximum record limit is 10. Returns the ID of the filter that is currently in context. <ideas:profileListOutputLink>.Id • NumComments • Status • Title • VoteTotal In addition to the method listed above. You can use the <ideas:listOutputLink>.000 records. If this is false. or the home page. and <ideas:detailOutputLink> components to display profile pages as well as idea list and detail pages (see the examples below).CreatedBy. there are more records than you can process using the list controller. Note: The methods inherited from the StandardSetController Class cannot be used to affect the list of ideas returned by the getIdeaList method. if known.Id • LastComment. Indicates whether there are more records in the set than the maximum record limit.Id • CreatedDate • Id • LastCommentDate • LastComment.Reference Visualforce Classes Name getIdeaList Arguments Return Type Idea[] Description Returns the list of read-only ideas in the current page set. Void Boolean Returns the first page of records.CreatedBy. The following table lists the inherited methods.CommunityNickname • CreatedBy. Name cancel first getCompleteResult Arguments Return Type Description System.CommunityNickname • LastComment. Indicates whether there are more records after the current page set. Integer Integer sObject Returns the page number of the current page set. Returns the next page of records.This retrieves the prototype object contained within the class. or the home page.IdeaStandardSetController)controller. Note that the first page returns 1. This list is immutable. and is used for performing mass updates. if known. Returns the list of sObjects in the current page set.SelectOption[] Returns a list of the listviews available to the current user. Sets the number of records in each page set. Sets the page number. String filterId Void Sets the filter ID of the controller. Returns the list of sObjects that have been selected.e. it returns a PageReference to the original page. setFilterID setpageNumber setPageSize setSelected Integer pageNumber Void Integer pageSize sObjects[] selectedRecords Void Void Example: Displaying a Profile Page The following example shows how an IdeaStandardSetController object can be used in the constructor for a custom list controller: public class MyIdeaProfileExtension { private final ApexPages.IdeaStandardSetController ideaSetController.IdeaStandardSetController controller) { ideaSetController = (ApexPages. After this operation is finished. // modify ideas here 478 . Returns the previous page of records. you can't call clear() on it. public MyIdeaProfileExtension(ApexPages.Reference Visualforce Classes Name getHasPrevious getListViewOptions getPageNumber getPageSize getRecord Arguments Return Type Boolean Description Indicates whether there are more records before the current page set. getRecords sObject[] Integer sObject[] Void Void Void getResultSize getSelected last next previous save System. Returns the last page of records. } public List<Idea> getModifiedIdeas() { Idea[] ideas = ideaSetController. Returns the number of records included in each page set.getIdeaList(). i. Set the selected records.PageReference Inserts new records or updates existing records that have been changed. Returns the sObject that represents the changes to the selected records. Returns the number of records in the set. System. id}" page="viewPage"> {!ideadata. } public List<Idea> getModifiedIdeas() { 479 .title} </ideas:detailOutputLink> <br/><br/> <apex:outputText>{!idea. This page must be named profilePage in order for this example to work: <!-.IdeaStandardSetController ideaSetController.Reference Visualforce Classes return ideas. public MyIdeaListExtension (ApexPages.body}</apex:outputText> </apex:pageBlock> </apex:page> Example: Displaying a List of Top.page named viewPage --> <apex:page standardController="Idea"> <apex:pageBlock title="Idea Section"> <ideas:detailOutputLink page="viewPage" ideaId="{!idea. Recent. submitted ideas. } } The following Visualforce markup shows how the IdeaStandardSetController example shown above and the <ideas:profileListOutputLink> component can display a profile page that lists the recent replies. This page must be named viewPage in order for this example to work: <!-. the page automatically shows the profile page for the current logged in user.IdeaStandardSetController controller) { ideaSetController = (ApexPages.title}</ideas:detailoutputlink> </apex:dataList> </apex:pageBlock> </apex:page> In the previous example. and Most Popular Ideas and Comments The following example shows how an IdeaStandardSetController object can be used in the constructor for a custom list controller: Note: You must have created at least one idea for this example to return any ideas. public class MyIdeaListExtension { private final ApexPages.page named profilePage --> <apex:page standardController="Idea" extensions="MyIdeaProfileExtension" recordSetVar="ideaSetVar"> <apex:pageBlock > <ideas:profileListOutputLink sort="recentReplies" page="profilePage"> Recent Replies</ideas:profileListOutputLink> | <ideas:profileListOutputLink sort="ideas" page="profilePage">Ideas Submitted </ideas:profileListOutputLink> | <ideas:profileListOutputLink sort="votes" page="profilePage">Ideas Voted </ideas:profileListOutputLink> </apex:pageBlock> <apex:pageBlock > <apex:dataList value="{!modifiedIdeas}" var="ideadata"> <ideas:detailoutputlink ideaId="{!ideadata. Because this example does not identify a specific user ID.IdeaStandardSetController)controller.id}">{!idea. and votes associated with a user. the <ideas:detailoutputlink> component links to the following Visualforce markup that displays the detail page for a specific idea. title} </ideas:detailOutputLink> <br/><br/> <apex:outputText>{!idea.id}" page="viewPage"> {!ideadata. and most popular ideas and comments.id}">{!idea.page named viewPage --> <apex:page standardController="Idea"> <apex:pageBlock title="Idea Section"> <ideas:detailOutputLink page="viewPage" ideaId="{!idea.page named listPage --> <apex:page standardController="Idea" extensions="MyIdeaListExtension" recordSetVar="ideaSetVar"> <apex:pageBlock > <ideas:listOutputLink sort="recent" page="listPage">Recent Ideas </ideas:listOutputLink> | <ideas:listOutputLink sort="top" page="listPage">Top Ideas </ideas:listOutputLink> | <ideas:listOutputLink sort="popular" page="listPage">Popular Ideas </ideas:listOutputLink> | <ideas:listOutputLink sort="comments" page="listPage">Recent Comments </ideas:listOutputLink> </apex:pageBlock> <apex:pageBlock > <apex:dataList value="{!modifiedIdeas}" var="ideadata"> <ideas:detailoutputlink ideaId="{!ideadata. top.getIdeaList(). the <ideas:detailoutputlink> component links to the following Visualforce markup that displays the detail page for a specific idea. This page must be named listPage in order for this example to work: <!-. } } The following Visualforce markup shows how the IdeaStandardSetController example shown above can be used with the <ideas:listOutputLink> component to display a list of recent. 480 . This page must be named viewPage.Reference Visualforce Classes Idea[] ideas = ideaSetController.body}</apex:outputText> </apex:pageBlock> </apex:page> See Also: Ideas Class KnowledgeArticleVersionStandardController Class KnowledgeArticleVersionStandardController objects offer article-specific functionality in addition to what is provided by the StandardController Class. // modify ideas here return ideas.title}</ideas:detailoutputlink> </apex:dataList> </apex:pageBlock> </apex:page> In the previous example. <!-. or they can be explicit relationships to fields. String category In addition to the method listed above.PageReference Deletes record and returns the PageReference of the delete page. System. cancel delete edit getId System. it's called by the controller's constructor. and save methods don't serve a function when used with the KnowledgeArticleVersionStandardController class. Name addFields Arguments List<String> fieldNames Return Type Void Description When a Visualforce page is loaded. If this method is called outside of the constructor. the fields accessible to the page are based on the fields referenced in the Visualforce markup.PageReference Returns the PageReference of the standard edit page. you must use the reset() method before calling addFields(). such as AccountId. String Returns the ID of the record that is currently in context.PageReference Returns the PageReference of the cancel page. The following table lists the inherited methods. based on the value of the id query string parameter in the Visualforce page URL. the KnowledgeArticleVersionStandardController class inherits all the methods associated with the StandardController Class. 481 .Reference Visualforce Classes Methods The KnowledgeArticleVersionStandardController object has the following specialized instance methods: Name getSourceId setDataCategory String categoryGroup Arguments Return Type String Void Description Returns the ID for the source object record when creating a new article from another object. The strings in fieldNames can either be the API name of a field. the edit.myField__c. System. This method should be called before a record has been loaded—typically. Note: Though inherited. delete. This method adds a reference to each field specified in fieldNames so that the controller can explicitly access those fields as well. This method is only for controllers used by dynamicVisualforce bindings. Specifies a default data category for the specified data category group when creating a new article. such as foo__r. For instructions. see “Defining Article Types” in the Salesforce online help.Reference Visualforce Classes Name getRecord Arguments Return Type SObject Description Returns the record that is currently in context. including fields from any related objects. must be queried using a SOQL expression. you create a class named AgentContributionArticleController that allows customer-support agents to see pre-populated fields on the draft articles they create while closing cases. For example: <apex:outputText value="{!account. This method is only for controllers used by dynamicVisualforce bindings.PageReference Returns the PageReference object of the standard detail page. Tip: You can work around this restriction by including a hidden component that references any additional fields that you want to query. Prerequisites: 1. save view System. Create an article type called FAQ. 2. For instructions. All other fields.PageReference Saves changes and returns the updated PageReference. Note that only the fields that are referenced in the associated Visualforce markup are available for querying on this SObject. In this example. For instructions. see “Creating and Modifying Category Groups” and “Adding Data Categories to Category Groups” in the Salesforce online help. and it must be called directly before addFields. based on the value of the id query string parameter in the Visualforce page URL.billingcity} {!account. Any changes made to the record prior to this method call are discarded.contacts}" rendered="false"/> reset Void Forces the controller to reacquire access to newly referenced fields. 3. System. Create a text custom field called Details. Create a category group called Geography and assign it to a category called USA. Hide the component from display by setting the component's rendered attribute to false. see “Adding Custom Fields to Article Types” in the Salesforce online help. 482 . Example The following example shows how a KnowledgeArticleVersionStandardController object can be used to create a custom extension controller. This method is only used if addFields is called outside the constructor. Click Save. Description FROM Case WHERE Id=:sourceId]. caseId). ctl. Case c = [SELECT Subject.put('details__c'. Create a category group called Topics and assign it a category called Maintenance. ctl. SObject article = ctl. '1'). // Only one category per category group can be specified. ctl. System.selectDataCategory('Topics'. String caseId = c. ApexPages. ApexPages. System.getSourceId()). article.override'.assertEquals(caseId. article.subject). ApexPages.KnowledgeArticleVersionStandardController as an argument public AgentContributionArticleController( ApexPages. 'From Case: '+c. String caseDesc = 'my test description'.KnowledgeArticleVersionStandardController ctl) { // This is the SObject for the new article.KnowledgeArticleVersionStandardController ctl = new ApexPages.currentPage(). FAQ__kav article = (FAQ__kav) ctl.getSourceId(). //It can optionally be cast to the proper article type. new AgentContributionArticleController(ctl).getRecord().getParameters(). ctl.getRecord().selectDataCategory('Geography'.assertEquals(caseDesc. } /** Test for this custom extension controller */ public static testMethod void testAgentContributionArticleController() { String caseSubject = 'my test'.assertEquals('From Case: '+caseSubject. // This returns the ID of the case that was closed. insert c.get('details__c')).description). Case c = new Case(). /** Custom extension controller for the simplified article edit page that appears when an article is created on the close-case page.getRecord(). This associates the article type specified in the new class with the article type assigned to closed cases. c. Click Edit. } } If you created the custom extension controller for the purpose described in the previous example (that is.KnowledgeArticleVersionStandardController(new FAQ__kav()). 483 .Reference Visualforce Classes 4.get('title')).id. */ public class AgentContributionArticleController { // The constructor must take a ApexPages. String sourceId = ctl.put('title'. 3. // This overrides the default behavior of pre-filling the // title of the article with the subject of the closed case. System. // For example. 4.debug('Created Case: ' + caseId).subject= caseSubject. Assign the class to the Use Apex customization field. c.currentPage(). to modify submitted-via-case articles). System.getRecord().put('sfdc.getParameters().'USA').c. Log into your Salesforce organization and click Your Name > Setup > Customize > Knowledge > Settings.description = caseDesc. 2. complete the following steps after creating the class: 1.'Maintenance').put('sourceId'. ctl. Severity.Message(ApexPages. If there is an inputField component bound to the field with an error. summary is the String used to summarize the message. summary). specify the severity of the message. All messages are added to the pages error collection. you must use the message class for collecting errors.Severity String ApexPages.Severity enum values. For example: ApexPages. this method returns null.Message(ApexPages.severity is the enum that is determines how severe a message is. If no detail String was specified.Message myMsg = new ApexPages. both custom and standard. Returns the value of the detail parameter used to create the message. you can instantiate a Message in one of the following ways: • ApexPages. see Validation Rules and Standard Controllers in the Visualforce Developer's Guide. getDetail String getSeverity getSummary ApexPages.Message(ApexPages.FATAL. this method returns null. where ApexPages. If no label is defined.Message myMsg = new ApexPages. • ApexPages. The table below describes the instance methods for Message. Returns the summary String used to create the message.severity. Name getComponentLabel Arguments Return Type String Description Returns the label of the associated inputField component. and detail is the String used to provide more detailed information about the error.Message myMsg = new ApexPages. severity is the enum that is determines how severe a message is.severity. and summary is the String used to summarize the message. The following are the valid values: • • • • • CONFIRM ERROR FATAL INFO WARNING 484 .Reference Visualforce Classes Message Class When using a standard controller. 'my error msg'). detail). that occur when the end user saves the page are automatically added to the page error collections. all validation errors. Instantiation In a custom controller or controller extension. If your application uses a custom controller or extension.Severity Enum Using the ApexPages. Methods The Message methods are all called by and operate on a particular instance of Message. Returns the severity enum used to create the message. summary. where ApexPages. the message is added to the components error collection. For more information. PageReference Class A PageReference is a reference to an instantiation of a page. Use a PageReference object: • • To view or set query string parameters and values for a page To navigate the user to a different page as the result of an action method Instantiation In a custom controller or controller extension. setting 'partialURL' to '/' + 'recordID' refers to the detail page for the specified record. the platform recognizes that this controller or controller extension is dependent on the existence of the specified page and will prevent the page from being deleted while the controller or extension exists.Reference Visualforce Classes All enums have access to standard methods.google. • PageReference pageRef = new PageReference('partialURL').com platform. Name getAnchor getContent Arguments Return Type String Blob Description Returns the name of the anchor referenced in the page’s URL. you can refer to or instantiate a PageReference in one of the following ways: • Page. setting 'partialURL' to '/apex/HelloWorld' refers to the Visualforce page located at http://mySalesforceInstance/apex/HelloWorld. such as name and value. This syntax is less preferable for referencing other Visualforce pages than Page. Creates a PageReference for an external URL. Likewise.existingPageName Refers to a PageReference for a Visualforce page that has already been saved in your organization. Among other attributes. • PageReference pageRef = new PageReference('fullURL'). Consequently. The content of the returned Blob is 485 . Creates a PageReference to any page that is hosted on the Force. PageReferences consist of a URL and a set of query parameter names and values.currentPage(). Returns the output of the page. rather than referenced at compile time.com'). Methods PageReference methods are all called by and operate on a particular instance of a PageReference.existingPageName because the PageReference is constructed at runtime. For example: PageReference pageRef = ApexPages. The table below describes the instance methods for PageReference. For example: PageReference pageRef = new PageReference('http://www. Runtime references are not available to the referential integrity system. the platform doesn't recognize that this controller or controller extension is dependent on the existence of the specified page and won't issue an error message to prevent user deletion of the page. For example. By referring to a page in this way. That is. You can also instantiate a PageReference object for the current page with the currentPage ApexPages method. the part of the URL after the hashtag (#). as displayed to a user in a Web browser. For a description of request headers. getHeaders Map<String.put('Date'. Used in conjunction with the Cookie class. System. and the value string contains the value of the header.getHeaders().Cookie[]> Returns a map of cookie names and cookie objects. 486 . it returns the HTML. If the page is rendered as a PDF. an ExecutionException is thrown. getContentAsPDF Blob Returns the page as a PDF. Only returns cookies with the “apex__” prefix set by the setCookies method. use the toString Blob method. To access the content of the returned HTML as a string. where the key is a String of the cookie name and the value contains the list of cookie objects with that name. This method can't be used in: • • • • • Triggers Scheduled Apex Batch jobs Test methods Apex email services If there's an error on the Visualforce page. If the page is not rendered as a PDF. String> Returns a map of the request headers. This method can't be used in: • • • • • Triggers Scheduled Apex Batch jobs Test methods Apex email services getCookies Map<String. it returns the PDF. see Request Headers on page 488. Note: If you use getContent in a test method. where the key string contains the name of the header.Reference Visualforce Classes Name Arguments Return Type Description dependent on how the page is rendered. '9/9/99'). a blank PDF is generated when used with a Visualforce page that is supposed to render as PDF. This map can be modified and remains in scope for the PageReference object. you could do: PageReference. regardless of the <apex:page> component's renderAs attribute. For instance. PageReference Sets the URL’s anchor reference to the specified string. For more information. getUrl String Returns the relative URL associated with the PageReference when it was originally defined. myID). Void Creates a list of cookie objects. If you use a cookie value to generate dynamic content.getParameters(). This map can be modified and remains in scope for the PageReference object. String> Returns a map of the query string parameters that are included in the page URL. you could do: PageReference. After you create a cookie. while the value string contains the value of the parameter. including any query string parameters and anchors. For example. For instance. see “Caching Force. The key string contains the name of the parameter.put('id'.com domain. characters such as @ are replaced with a percent sign and their hexadecimal representation. regardless of whether the redirect attribute is set to true or false. https://Salesforce_instance/apex/my_page#anchor1. that is. setCookies Cookie[] cookies • • • • 487 . Note that if the URL of the PageReference object is set to a website outside of the salesforce. the properties of the cookie can't be changed. Setting a cookie's value to null sends a cookie with an empty string value instead of setting an expired attribute. setAnchor String Anchor System. Be careful when storing sensitive information in cookies. the redirect always occurs. Pages are cached regardless of a cookie value.Reference Visualforce Classes Name getParameters Arguments Return Type Description Map<String. Important: • Cookie names and values set in Apex are URL encoded. Used in conjunction with the Cookie class.com Sites Pages” in the Salesforce online help. getRedirect Boolean Returns the current value of the PageReference object's redirect attribute. you should disable page caching. The setCookies method adds the prefix “apex__” to the cookie names. and extension support of the program that initiated this request. X-Salesforce-Forwarded-To The fully qualified domain name of the Salesforce instance that is handling this request. This header is optional on other requests when HTTP/1.com Site requests and My Domain requests. Note that if the URL of the PageReference object is set to a website outside of the salesforce. Therefore. regardless of whether the redirect attribute is set to true or false. and can be changed without notice. and flushes the view state. such as a Web browser. a redirect is performed through a client side redirect.com domain. This header is optional and can be overridden in most browsers to be a different value.1. The URL that is either included or linked to the current request's URL. or to a page with a different controller or controller extension. If set to true.Reference Visualforce Classes Name setRedirect Arguments Boolean redirect Return Type Description System. the redirect is a server-side forward that preserves the view state if and only if the target page uses the same controller and contains the proper subset of extensions used by the source page. This header is always set on HTTP and HTTPS requests that are initiated outside of Salesforce's data centers. If this header exists and has a non-blank value. the source IP address might be altered. Otherwise. The source IP address of the request. This header is always set on HTTP and HTTPS requests that are initiated outside of Salesforce's data centers. This header is always set on Force. the redirect always occurs. This header is optional. and no longer the original client IP address. this means that the request is using HTTPS. the request is using HTTP. This type of redirect performs an HTTP GET request. Note: If a request passes through a content delivery network (CDN) or proxy server. Header Host Description The host name requested in the request URL. The contents of a non-blank value are not defined by this API. If set to false. this header should not be relied upon.PageReference Sets the value of the PageReference object's redirect attribute. version. Request Headers The following table is a non-exhaustive list of headers that are set on requests. Referer User-Agent CipherSuite X-Salesforce-SIP 488 .0 is used instead of HTTP/1. The name. which uses POST. the user navigates to the URL specified by the PageReference.get('Id')]. In this example.Reference Visualforce Classes Example: Retrieving Query String Parameters The following example shows how to use a PageReference object to retrieve a query string parameter in the current page URL. the getAccount method uses the ApexPages namespace: • • • First the currentPage method returns the PageReference instance for the current page. insert account. Then a call to the get method specifying id returns the value of the id parameter itself. The following example shows how this can be implemented with a save method.setRedirect(true). Using the page reference. Name FROM Account WHERE Id = :ApexPages. To access id. PageReference acctPage = new ApexPages. you must associate the Visualforce page with a valid account record in the URL. 489 . the resulting URL should be: https://Salesforce_instance/apex/MyFirstPage?id=001D000000IRt53 The getAccount method uses an embedded SOQL query to return the account specified by the id parameter in the URL of the page. including its query string parameters. </apex:pageBlock> </apex:page> Note: For this example to render properly.view().StandardController(account). public Account getAccount() { if(account == null) account = new Account(). } } The following page markup calls the getAccount method from the controller above: <apex:page controller="MyController"> <apex:pageBlock title="Retrieving Query String Parameters"> You are viewing the {!account. In this example. the PageReference returned by the save method redirects the user to the detail page for the account record that was just saved: public class mySecondController { Account account. PageReference returns a reference to a Visualforce page. use the getParameters method to return a map of the specified query string parameter names and values. if 001D000000IRt53 is the account ID. For example.name} account. Example: Navigating to a New Page as the Result of an Action Method Any action method in a custom controller or controller extension can return a PageReference object as the result of the method. return account. } public PageReference save() { // Add the account to the database. the getAccount method references the id query string parameter: public class MyController { public Account getAccount() { return [SELECT Id. // Send the user to the detail page for the new account. If the redirect attribute on the PageReference is set to true.currentPage(). acctPage.getParameters(). Name getDisabled Arguments Return Type Boolean Description Returns the current value of the SelectOption object's isDisabled attribute. When a user clicks Save. The table below describes the instance methods for SelectOption. so that a user cannot select it as an option. or selectRadio component.site}"/> </apex:pageBlockSection> </apex:pageBlock> </apex:form> </apex:page> SelectOption Class A SelectOption object specifies one of the possible values for a Visualforce selectCheckboxes. and a value that is returned to the controller if the option is selected. A SelectOption can also be displayed in a disabled state. where value is the String that is returned to the controller if the option is selected by a user. he or she is redirected to the detail page for the account just created: <apex:page controller="mySecondController" tabStyle="Account"> <apex:sectionHeader title="New Account Edit Page" /> <apex:form> <apex:pageBlock title="Create a New Account"> <apex:pageBlockButtons location="bottom"> <apex:commandButton action="{!save}" value="Save"/> </apex:pageBlockButtons> <apex:pageBlockSection title="Account Information"> <apex:inputField id="accountName" value="{!account.Reference Visualforce Classes return acctPage. } } The following page markup calls the save method from the controller above. If isDisabled is set to true. and label is the String that is displayed to the user as the option choice. label). Methods The SelectOption methods are all called by and operate on a particular instance of SelectOption. label. but can still view it. but can still view it. the user can view the option. label is the String that is displayed to the user as the option choice.name}"/> <apex:inputField id="accountSite" value="{!account. If 490 . isDisabled). the user can both view and select the option. It consists of a label that is displayed to the end user. and isDisabled is a Boolean that. if true. Because a value for isDisabled is not specified. but cannot select it. • SelectOption option = new SelectOption(value. Instantiation In a custom controller or controller extension. you can instantiate a SelectOption in one of the following ways: • SelectOption option = new SelectOption(value. specifies that the user cannot select the option. selectList. where value is the String that is returned to the controller if the option is selected by a user. } public String[] getCountries() { 491 . Sets the value of the option value that is returned to the controller if a user selects the option.'US')). Returns the option value that is returned to the controller if a user selects the option. If itemEscaped is set to false. Sets the value of the option label that is displayed to the user. If isDisabled is set to false. In the following custom controller. If isDisabled is set to true. items are rendered as written. items are rendered as written.add(new SelectOption('US'. sensitive HTML and XML characters are escaped in the HTML output generated by this component. If itemEscaped is set to true. If itemEscaped is set to false. the user can both view and select the option.Reference Visualforce Classes Name Arguments Return Type Description isDisabled is set to false. options. options. } public List<SelectOption> getItems() { List<SelectOption> options = new List<SelectOption>(). Returns the option label that is displayed to the user. Sets the value of the SelectOption object's itemEscaped attribute. getEscapeItem Boolean Returns the current value of the SelectOption object's itemEscaped attribute.'Canada')). sensitive HTML and XML characters are escaped in the HTML output generated by this component.add(new SelectOption('CANADA'. but cannot select it. If itemEscaped is set to true. options.'Mexico')). the getItems method defines and returns the list of possible SelectOption objects: public class sampleCon { String[] countries = new String[]{}. public PageReference test() { return null. the user can both view and select the option. return options. Sets the value of the SelectOption object's isDisabled attribute. getLabel getValue setDisabled String String Boolean isDisabled Void setEscapeItem Boolean itemsEscaped Void setLabel setValue String l String v Void Void Example The following example shows how a list of SelectOptions objects can be used to provide possible values for a selectCheckboxes component on a Visualforce page. the user can view the option.add(new SelectOption('MEXICO'. the <apex:selectOptions> tag uses the getItems method from the controller above to retrieve the list of possible values. Name addFields Arguments List<String> fieldNames Return Type Void Description When a Visualforce page is loaded. Methods StandardController methods are all called by and operate on a particular instance of a StandardController.Reference Visualforce Classes return countries..StandardController(sObject).countries = countries. This method adds a reference to each field specified in fieldNames so that the controller can explicitly access those fields as well.. 492 . the options are displayed as checkboxes: <apex:page controller="sampleCon"> <apex:form> <apex:selectCheckboxes value="{!countries}"> <apex:selectOptions value="{!items}"/> </apex:selectCheckboxes><br/> <apex:commandButton value="Test" action="{!test}" rerender="out" status="status"/> </apex:form> <apex:outputPanel id="out"> <apex:actionstatus id="status" startText="testing.StandardController sc = new ApexPages. } } In the following page markup. The table below describes the instance methods for StandardController. Instantiation You can instantiate a StandardController in the following way: ApexPages. StandardController is the data type of the single argument in the extension class constructor. the fields accessible to the page are based on the fields referenced in the Visualforce markup."> <apex:facet name="stop"> <apex:outputPanel> <p>You have selected:</p> <apex:dataList value="{!countries}" var="c">{!c}</apex:dataList> </apex:outputPanel> </apex:facet> </apex:actionstatus> </apex:outputPanel> </apex:page> StandardController Class StandardController objects reference the pre-built Visualforce controllers provided by salesforce. } public void setCountries(String[] countries) { this.com. The only time it is necessary to refer to a StandardController object is when defining an extension for a standard controller. Because <apex:selectOptions> is a child of the <apex:selectCheckboxes> tag. Note that only the fields that are referenced in the associated Visualforce markup are available for querying on this SObject. including fields from any related objects.myField__c.contacts}" rendered="false"/> getRecord SObject reset Void Forces the controller to reacquire access to newly referenced fields. Tip: You can work around this restriction by including a hidden component that references any additional fields that you want to query. This method is only for controllers used by dynamicVisualforce bindings. All other fields. System.PageReference Deletes record and returns the PageReference of the delete page. 493 . Hide the component from display by setting the component's rendered attribute to false. For example: <apex:outputText value="{!account. such as foo__r. Any changes made to the record prior to this method call are discarded. such as AccountId.Reference Visualforce Classes Name Arguments Return Type Description This method should be called before a record has been loaded—typically. This method is only used if addFields is called outside the constructor. must be queried using a SOQL expression. based on the value of the id query string parameter in the Visualforce page URL. based on the value of the id query string parameter in the Visualforce page URL. String Returns the ID of the record that is currently in context. The strings in fieldNames can either be the API name of a field. Returns the record that is currently in context. you must use the reset() method before calling addFields(). or they can be explicit relationships to fields. System. If this method is called outside of the constructor. and it must be called directly before addFields. cancel delete edit getId System. it's called by the controller's constructor.billingcity} {!account.PageReference Returns the PageReference of the cancel page.PageReference Returns the PageReference of the standard edit page. } } The following Visualforce markup shows how the controller extension from above can be used in a page: <apex:page standardController="Account" extensions="myControllerExtension"> {!greeting} <p/> <apex:form> <apex:inputField value="{!account.PageReference Returns the PageReference object of the standard detail page. or as extensions of.Reference Visualforce Classes Name Arguments Return Type Description This method is only for controllers used by dynamicVisualforce bindings. This is a single sObject contained within the Visualforce StandardSetController class. the pre-built Visualforce list controllers provided by Salesforce. } public String getGreeting() { return 'Hello ' + acct. public myControllerExtension(ApexPages. those values are used during the save action.name}"/> <p/> <apex:commandButton value="Save" action="{!save}"/> </apex:form> </apex:page> StandardSetController Class StandardSetController objects allow you to create list controllers similar to.id + ')'. If the prototype object's fields are set.PageReference Saves changes and returns the updated PageReference.StandardController stdController) { this. Instantiation You can instantiate a StandardSetController in either of the following ways: 494 . Example The following example shows how a StandardController object can be used in the constructor for a standard controller extension: public class myControllerExtension { private final Account acct.getRecord(). // The extension constructor initializes the private member // variable acct by using the getRecord method from the standard // controller. meaning that the values are applied to every record in the set controller's collection. System. save view System. Note: Fields that are required in other Salesforce objects will keep the same requiredness when used by the prototype object.name + ' (' + acct. The StandardSetController class also contains a prototype object.acct = (Account)stdController. This is useful for writing pages that perform mass updates (applying identical changes to fields within a collection of objects). • From a query locator: ApexPages.000 records.Reference Visualforce Classes • From a list of sObjects: List<account> accountList = [SELECT Name FROM Account LIMIT 20]. instantiating StandardSetController with a list of more than 10.getQueryLocator([SELECT Name.000 records causes a LimitException to be thrown. Methods StandardSetController methods are all called by and operate on a particular instance of a StandardSetController.StandardSetController(Database.PageReference Returns the PageReference of the original page.SelectOption[] Returns a list of the listviews available to the current user. ApexPages. Note that the first page returns 1. and is used for performing mass updates. Void Boolean Returns the first page of records. Indicates whether there are more records before the current page set.CloseDate FROM Opportunity])).StandardSetController ssc = new ApexPages. If this is false. The maximum record limit is 10. 495 . However. getFilterId getHasNext getHasPrevious getListViewOptions getPageNumber getPageSize getRecord String Boolean Boolean System. and instead truncates the records to the limit. The table below describes the instance methods for StandardSetController.StandardSetController(accountList). if known. Integer Integer sObject Returns the page number of the current page set. there are more records than you can process using the list controller. Note: The maximum record limit for StandardSetController is 10.This retrieves the prototype object contained within the class. or the home page.StandardSetController ssc = new ApexPages. Indicates whether there are more records in the set than the maximum record limit. Returns the ID of the filter that is currently in context.000 records doesn’t throw an exception.000 records. Instantiating StandardSetController using a query locator returning more than 10. Name cancel first getCompleteResult Arguments Return Type Description System. Returns the sObject that represents the changes to the selected records. Indicates whether there are more records after the current page set. Returns the number of records included in each page set. Returns the next page of records. Returns the last page of records. Returns the previous page of records. Sets the number of records in each page set. if known. Set the selected records.getQueryLocator( [SELECT Name. Sets the page number.getRecords().Name}"/> <apex:column value="{!o. i. } } The following Visualforce markup shows how the controller above can be used in a page: <apex:page controller="opportunityList2Con"> <apex:pageBlock> <apex:pageBlockTable value="{!opportunities}" var="o"> <apex:column value="{!o. String filterId Void Sets the filter ID of the controller. Returns the list of sObjects that have been selected. Returns the number of records in the set.PageReference Inserts new records or updates existing records that have been changed. you can't call clear() on it. or the home page.e. After this operation is finished.Reference Visualforce Classes Name getRecords Arguments Return Type sObject[] Integer sObject[] Void Void Void Description Returns the list of sObjects in the current page set. it returns a PageReference to the original page.StandardSetController(Database.StandardSetController setCon { get { if(setCon == null) { setCon = new ApexPages. } return setCon.StandardSetController must be instantiated // for standard list controllers public ApexPages. } set. setFilterID setpageNumber setPageSize setSelected Integer pageNumber Void Integer pageSize sObjects[] selectedRecords Void Void Example The following example shows how a StandardSetController object can be used in the constructor for a custom list controller: public class opportunityList2Con { // ApexPages.CloseDate}"/> </apex:pageBlockTable> 496 . getResultSize getSelected last next previous save System. This list is immutable. } // Initialize setCon and return a list of records public List<Opportunity> getOpportunities() { return (List<Opportunity>) setCon. CloseDate FROM Opportunity])). The returned variable value comes from whichever flow the interview is currently running. the Flow. The flow variable can be in the flow embedded in the Visualforce page. getVariableValue String variableName Sample The following sample uses the getVariableValue method to obtain breadcrumb (navigation) information from the flow embedded in the Visualforce page.} else aBreadCrumb = (String) myFlow. which enables a Visualforce controller to access the value of a flow variable embedded in the Visualforce page. not at compile time.Interview class. the method returns null.} public String getBreadCrumb() { String aBreadCrumb.Interview Class The Flow. Methods The following is the instance method of the Flow. public class SampleContoller { //Instance of the flow public Flow.Interview class provides advanced Visualforce controller access to flows. return(aBreadCrumb==null ? 'Home': aBreadCrumb).Interview class has one method. or in a separate flow that is called by a subflow element. if (myFlow==null) { return 'Home'.Interview. The variableName argument specifies the unique name of the flow variable. the Visualforce page can provide users with breadcrumbs regardless of which flow the interview is running.getVariableValue('vaBreadCrumb'). Usage Used with Visual Workflow. and each of the referenced flows also contains a vaBreadCrumb variable.Reference Flow. } } 497 . or in a separate flow called by a subflow element. If the specified variable can’t be found in that flow. If that flow contains subflow elements.Flow_Template_Gallery myFlow {get. set.Interview Class </apex:pageBlock> </apex:page> Flow. Method Arguments Return Type Object Description Returns the value of the specified flow variable. This method checks for the existence of the variable at run time only. See http://java. If you reach that limit. // You can use the system static method assert to verify the match System.html. Any Java-based regular expression strings can be easily imported into your Apex code. instantiate a new Pattern object "MyPattern" Pattern MyPattern = Pattern.matches()).assert(MyMatcher.matcher('aaaaab'). All further actions are then performed using the Matcher object.5.000 times.Reference Pattern and Matcher Classes Pattern and Matcher Classes A regular expression is a string that is used to match another string. you receive a runtime error. Using Patterns and Matchers A Pattern is a compiled representation of a regular expression. Patterns and Matchers. as shown in the following illustration: Figure 10: Many Matcher objects can be created from the same Pattern object Regular expressions in Apex follow the standard syntax for regular expressions used in Java. as well as regular expressions. after you compile a regular expression into a Pattern object. you only use the Pattern object once to create a Matcher object. Apex supports the use of regular expressions through its Pattern and Matcher classes.0/docs/api/index. // Then instantiate a new Matcher object "MyMatcher" Matcher MyMatcher = MyPattern. using a specific syntax.com/j2se/1.000. 498 . Note: Salesforce limits the number of times an input sequence for a regular expression can be accessed to 1. Generally. Note: In Apex. Patterns are used by Matchers to perform match operations on a character string.sun. Most regular expressions are first compiled into a Pattern object: only the String split method takes a regular expression that isn't compiled.compile('a*b'). Many Matcher objects can share the same Pattern object. For example: // First. All regular expressions are specified as strings.html?java/util/regex/Pattern. are based on their counterparts in Java. Reference Pattern and Matcher Classes If you are only going to use a regular expression once.region(start.region(0. using the lookingAt method Scan the Matcher object's input string for the next substring that matches the pattern using the find method Each of these methods returns a Boolean indicating success or failure.region(MyMatcher.matches('a*b'. this method returns the subsequence that was matched. Start of the Region Specify explicitly End of the Region Leave unchanged MyMatcher. that is. start: Once a match is made. this method returns the position in the string of the first character that was matched. However. For example. and you can query the region's end points by using the regionStart and regionEnd methods. a Matcher object can be used to perform the following types of match operations: • • • Match the Matcher object's entire input string against the pattern using the matches method Match the Matcher object's input string against the pattern.regionStart(). by using the following Matcher class methods: • • • end: Once a match is made. The default region for a Matcher object is always the entirety of the input string. end). Code Example Leave unchanged Specify explicitly MyMatcher. end). Once created. this method returns the position in the match string after the last character that was matched. 'aaaaab'). starting at the beginning but without matching the entire region. you can change the start and end points of a region by using the region method. Using Regions A Matcher object finds matches in a subset of its input string called a region.regionEnd()). Using Match Operations A Matcher object performs match operations on a character sequence by interpreting a Pattern. 499 . use the Pattern class matches method to compile the expression and match a string against it in a single invocation. MyMatcher. The following table provides examples of how to set one value without setting the other. what was found. A Matcher object is instantiated from a Pattern by the Pattern's matcher method. Reset to the default Specify explicitly MyMatcher. The region method requires both a start and an end value. After you use any of these methods. group: Once a match is made. you can find out more information about the previous match. the following is equivalent to the code above: Boolean Test = Pattern. there are four capturing groups: 1. all text located outside of a region is not searched. However.assert(myMatcher. and your region was only the word “STRING”: This is a concatenated STRING of cats and dogs. that is. a region is delimited by anchoring bounds. In regular expression syntax. its previously captured value. using transparent bounds it is possible to search the text outside of a region.'a' followed by 'b' not at all. You would use this when you are parsing a string and want to do additional work with it after you have found a match. System.hitEnd()). If you searched for the word “cat”. In the following example. ((A)(B(C))) (A) (B(C)) (C) Group zero always stands for the entire expression. You can specify which type of bounds a region has by using the useTransparentBounds method. Suppose you were searching the following string. Understanding Capturing Groups During a matching operation. the region has opaque bounds. the string passed in with the Matcher object matches the pattern since (a(b)?) matches the string 'ab' . These matching substrings are called capturing groups. if any.Reference Pattern and Matcher Classes Using Bounds By default. and group 1 contains // the substring that most recently matched--in this case. that was returned by one of the Matcher class match operations. For example. and + means match 1 or more times. even if the region boundaries have been moved from the start and end of the input string. Capturing groups are numbered by counting their opening parentheses from left to right. 'a'. It then matches the last 'a' . Pattern and Matcher Example The Matcher class end method returns the position in the match string after the last character that was matched. which means that the line anchors (such as ^ or $) match at the region boundaries.'a' followed by 'b' once. The captured input associated with a group is always the substring of the group most recently matched. the line anchors match only the true ends of the input string.compile('(a(b)?)+').matches() && myMatcher. such as find the next match. By default. You can specify whether a region uses anchoring bounds with the useAnchoringBounds method. ? means match once or not at all. Transparent bounds are only used when a region no longer contains the entire input string. matcher myMatcher = myPattern. By default. If a group is evaluated a second time using one of the match operations. // We have two groups: group 0 is always the whole pattern. 500 . each substring of the input string that matches the pattern is saved. 4. If you set useAnchoringBounds to false. 2. that is. 3. in the regular expression string ((A)(B(C))). a region always uses anchoring bounds.matcher('aba'). you wouldn't receive a match unless you had transparent bounds set. is retained if the second evaluation fails. pattern myPattern = pattern. end(0) == 3 && myMatcher. for(Lead lead:leads) { // Ignore leads with a null email if(lead.Lead>().groupCount() == 2 && myMatcher.smithco. For example.[\\w]+$)'). // and since both groups used the last input letter.com' or 'john@smithco. email addresses are normalized and duplicates are reported if there is a different top-level domain name or subdomain for similar email addresses.compile('(?<=@)((?![\\w]+\\. } } } // Now search the database looking for duplicates for(Lead[] leadsCheck:[SELECT Id. 501 .group(0) == 'aba' && myMatcher.Email).end() == myMatcher. the following is true: System.assert(myMatcher.Duplicate_Key__c).end(0)).email. that offset is 3 // Remember the offset starts its count at 0.keySet()]) { for(Lead lead:leadsCheck) { // If there's a duplicate. // Look for duplicates in the batch if(leadMap. duplicate_key__c FROM Lead WHERE duplicate_key__c IN :leadMap. In the following example.group(1) == 'a'). else { // Keep the key in the duplicate key custom field lead.replaceAll('').containsKey(lead. // Since group 0 refers to the whole pattern. So the following is also true: System. } } } } Pattern Methods The following are the system static methods for Pattern.Reference Pattern and Matcher Classes // So the following is true: System. add the error.matcher(lead.)|(\\.Duplicate_Key__c = emailKey.Email != null) { // Generate the key using the regular expression String emailKey = emailPattern.addError('Duplicate found in salesforce(Id: ' + lead.Id + ')').smithco is normalized to
[email protected]() == 3 && myMatcher.Lead> leadMap = new Map<String.addError('Duplicate found in batch').get(lead. lead).end(1) == 3). class normalizeEmailAddresses{ public void hasDuplicatesByDomain(Lead[] leads) { // This pattern reduces the email address to 'john@smithco' // from 'john@*.Duplicate_Key__c)) leadMap.containsKey(emailKey)) lead. john@fairway. // Since the offset after the last character matched is returned by end. leadMap.assert(myMatcher.email.assert(myMatcher.[\\w]+$) [\\w]+\\.*' Pattern emailPattern = Pattern.put(emailKey. if(leadMap. // Define a set for emailkey to lead: Map<String. matches(regExp. If s does not match the pattern. compiling it once and reusing it is more efficient than invoking this method each time. This method returns true if the string s matches the regular expression. quote String s String Returns a string that can be used to create a pattern that matches the string s as if it were a literal pattern. The substrings are placed in the list in the order in which they occur in the String. input).compile(regex). matches produces the same result as this code example: Pattern. Returns a list that contains each substring of the String that matches this pattern. Note that the following code example: Pattern. If a pattern is to be used multiple times. the resulting list has just one element containing the original String. false otherwise. Name matcher Arguments String regExp Return Type Matcher object String Description Creates a Matcher object that matches the input string regExp against this Pattern object.matches(). Compiles the regular expression regExp and tries to match it against s. Returns the regular expression from which this Pattern object was compiled. pattern split String s String[] split String regExp Integer limit String[] Returns a list that contains each substring of the String that is terminated either by the regular expression regExp that matches this 502 . The following are the instance methods for Pattern.Reference Pattern and Matcher Classes Name compile Arguments String regExp String regExp String s Return Type Pattern object Boolean Description Compiles the regular expression into a Pattern object. Metacharacters (such as $ or ^) and escape sequences in the input string are treated as literal characters with no special meaning. matcher(input). the list's length is no greater than limit. Matcher Methods The following are the system static methods for Matcher.end(). starting at one. Group zero denotes the entire pattern. Integer groupIndex Integer 503 . or by the end of the String. • If limit is non-positive then the pattern is applied as many times as possible and the list can have any length. and the list's last entry contains all input beyond the last matched delimiter. The characters in the returned string match the sequence of characters in s. Name end end Arguments Returns Integer Description Returns the position after the last matched character. the pattern is applied at most limit .end(0) is equivalent to m.Reference Pattern and Matcher Classes Name Arguments Return Type Description pattern.1 times. Name Arguments Return Type String Description Returns a literal replacement string for the specified string s. If the match was successful but the group itself did not match anything. • If limit is zero then the pattern is applied as many times as possible. Captured groups are indexed from left to right. this method returns -1. The optional limit parameter controls the number of times the pattern is applied and therefore affects the length of the list: • If limit is greater than zero. Metacharacters (such as $ or ^) and escape sequences in the input string are treated as literal characters with no special meaning. the list can have any length. and trailing empty strings are discarded. Returns the position after the last character of the subsequence captured by the group groupIndex during the previous match operation. so the expression m. quoteReplacement String s The following are the instance methods for Matcher. group(0) is equivalent to m. group String Returns the input subsequence returned by the previous match. This method returns the empty string when such a group successfully matches the empty string in the input. end. If the match succeeds. at the first character not matched by the previous match. Captured groups are indexed from left to right. Group zero denotes the entire pattern. more information can be obtained using the start. find Integer group Boolean Resets the Matcher object and then tries to find the next subsequence of the input sequence that matches the pattern. This method returns true if a subsequence of the input sequence matches this Matcher object's pattern. match the empty string. such as (a*). find Boolean Attempts to find the next subsequence of the input sequence that matches the pattern. Note that some groups. This method starts at the beginning of this Matcher object's region. This method returns true if a subsequence of the input sequence matches this Matcher object's pattern. If the match succeeds. match the empty string. 504 . or.Reference Pattern and Matcher Classes Name Arguments Returns Description See Understanding Capturing Groups. and group methods. end. see Using Regions. more information can be obtained using the start. starting at one. such as (a*). This method returns the empty string when such a group successfully matches the empty string in the input. null is returned. and group methods. if a previous invocation of the method was successful and the Matcher object has not since been reset. so the expression m. For more information. If the match was successful but the specified group failed to match any part of the input sequence. Note that some groups. group Integer groupIndex String Returns the input subsequence captured by the specified group groupIndex during the previous match operation.group(). and group methods. more information can be obtained using the start. groupCount Integer Returns the number of capturing groups in this Matching object's pattern. a Matcher object uses opaque region boundaries. Like the matches method. a Matcher object uses anchoring bounds regions. see Using Bounds. and group methods. Attempts to match the input sequence. it does not require the entire region be matched. unlike that method. false if it uses opaque bounds. more information can be obtained using the start. against the pattern.Reference Pattern and Matcher Classes Name Arguments Returns Description See Understanding Capturing Groups. If the match succeeds. see Using Bounds. See Using Regions. For more information. See Understanding Capturing Groups. this method always starts at the beginning of the region. When this method returns true. the boundaries of this Matcher object's region match start and end of line anchors such as ^ and $. end. By default. hasAnchoringBounds Boolean Returns true if the Matcher object has anchoring bounds. it is possible that more input would have changed the result of the last search. See Using Regions. If a Matcher object uses anchoring bounds. If the match succeeds. end. By default. hitEnd Boolean Returns true if the end of input was found by the search engine in the last match operation performed by this Matcher object. Group zero denotes the entire pattern and is not included in this count. For more information. lookingAt Boolean matches Boolean Attempts to match the entire region against the pattern. false otherwise. pattern Pattern object Returns the Pattern object from which this Matcher object was created. starting at the beginning of the region. 505 . hasTransparentBounds Boolean Returns true if the Matcher object has transparent bounds. and backslashes are used to escape literal characters in the replacement string. and the replacement string "-". If the Matcher object is to be used in further matching operations it should first be reset. Depending on the transparency boundaries being used. regionStart Integer Returns the start index (inclusive) of this Matcher object's region. See Using Regions. This method first resets the Matcher object. the input "aabfooaabfooabfoob". regionEnd Integer Returns the end index (exclusive) of this Matcher object's region. each match is replaced in the result by the replacement string. an invocation of this method on a Matcher object for that expression would yield the string "-foo-foo-foo-". Invoking this method changes this Matcher object's state.Reference Pattern and Matcher Classes Name region Arguments Integer start Integer end Returns Description Matcher object Sets the limits of this Matcher object's region. Characters that are not part of any match are appended directly to the result string. See Using Regions and Using Bounds. The region is the part of the input sequence that is searched to find a match. then sets the region to start at the index specified by start and end at the index specified by end. This method first resets the Matcher object. certain constructs such as anchors may behave differently at or around the boundaries of the region. 506 . Dollar signs may be treated as references to captured subsequences. replaceAll String s String Replaces every subsequence of the input sequence that matches the pattern with the replacement string s. then scans the input sequence looking for matches of the pattern. Given the regular expression a*b. See Using Regions. The replacement string may contain references to captured subsequences. Note that backslashes (\) and dollar signs ($) in the replacement string may cause the results to be different than if the string was treated as a literal replacement string. and backslashes are used to escape literal characters in the replacement string. start Integer 507 . Dollar signs may be treated as references to captured subsequences. If this method returns false and a match was found.Reference Pattern and Matcher Classes Name replaceFirst Arguments String s Returns String Description Replaces the first subsequence of the input sequence that matches the pattern with the replacement string s. For more information. reset Matcher object Resets this Matcher object. Invoking this method changes this Matcher object's state. then more input could cause the match to be lost. Resetting a Matcher object discards all of its explicit state information. Resetting a Matcher object discards all of its explicit state information. requireEnd Boolean Returns true if more input could change a positive match into a negative one. and the replacement string "cat". then more input might change the match but the match won't be lost. If the Matcher object is to be used in further matching operations it should first be reset. an invocation of this method on a Matcher object for that expression would return the string "zzzcatzzzdogzzz". reset String s Matcher Resets this Matcher object with the new input sequence s. If a match was not found. This method does not change whether the Matcher object uses anchoring bounds. If this method returns true. Note that backslashes (\) and dollar signs ($) in the replacement string may cause the results to be different than if the string was treated as a literal replacement string. You must explicitly use the useAnchoringBounds method to change the anchoring bounds. and a match was found. Returns the start index of the first character of the previous match. see Using Bounds. then requireEnd has no meaning. the input "zzzdogzzzdogzzz". Given the regular expression dog. If a Matcher object uses anchoring bounds. usePattern Pattern pattern Matcher object Changes the Pattern object that the Matcher object uses to find matches. If you specify false. non-anchoring bounds are used.start(0) is equivalent to m. This method causes the Matcher object to lose information about the groups of the last match that occurred. so the expression m. If you specify false. Matcher object Sets the transparency bounds for this Matcher object. If you specify true for this method. See Understanding Capturing Groups on page 500. opaque bounds are used. starting at one. a Matcher object uses anchoring bounds regions.Reference HTTP (RESTful) Services Classes Name start Arguments Integer groupIndex Returns Integer Description Returns the start index of the subsequence captured by the group specified by groupIndex during the previous match operation. Group zero denotes the entire pattern.start(). also called RESTful services. useAnchoringBounds Boolean b Matcher object Sets the anchoring bounds of the region for the Matcher object. see Using Bounds. If you specify true for this method. the Matcher object uses anchoring bounds. see Using Bounds on page 500. Captured groups are indexed from left to right. For more information. By default. By default. a Matcher object uses anchoring bounds regions. The Matcher object's position in the input is maintained. the Matcher object uses transparent bounds. For more information. using the following classes: • • • HTTP Classes Crypto Class EncodingUtil Class 508 . the boundaries of this Matcher object's region match start and end of line anchors such as ^ and $. useTransparentBounds Boolean b HTTP (RESTful) Services Classes You can access HTTP services. TRACE. PUT. log in to Salesforce and select Your Name > Setup > Security Controls > Remote Site Settings. POST. } } The previous example runs synchronously. To do this. meaning no further processing happens until the external Web service returns a response. HEAD.setEndpoint(url). Alternatively. PUT. req. POST.getBody(). For more information about the AJAX proxy.setMethod('GET'). // Instantiate a new HTTP request. and return a response HttpResponse res = h. Redirects if needed. you must add the remote site to a list of authorized remote sites in the Salesforce user interface. see AJAX Toolkit documentation. specify the method (GET) as well as the endpoint HttpRequest req = new HttpRequest(). The HttpRequest and HttpResponse classes support the following elements: • HttpRequest: ◊ ◊ ◊ ◊ ◊ • HTTP request types such as GET. req. // Send the request. Before you can access external servers from an endpoint or redirect endpoint using Apex or any other feature. and OPTIONS. DELETE. This example also shows accessing the body of the returned response: public class HttpCalloutSample { // Pass in the endpoint to be used using the string url public String getContent(String url) { // Instantiate a new http object Http h = new Http(). CONNECT. Request headers if needed. The following example shows an HTTP GET request made to the external server specified by the value of url that gets passed into the getContent method. you can use the @future annotation to make the callout run asynchronously. HttpRequest Class: Use this class to programmatically create HTTP requests like GET. Note: The AJAX proxy handles redirects and authentication challenges (401/407 responses) automatically.Reference HTTP (RESTful) Services Classes HTTP Classes These classes expose the general HTTP request/response functionality: • • • Http Class.send(req). and DELETE. ◊ Content of the response body. Read and connection timeouts. HttpResponse Class: Use this class to handle the HTTP response returned by HTTP. HttpResponse: ◊ The HTTP status code. return res. Content of the message body. Use this class to initiate an HTTP request and response. ◊ Response headers if needed. 509 . Dom. toString HttpRequest Class Use the HttpRequest class to programmatically create HTTP requests like GET. Retrieves the contents of the request header. Use the DOM Classes or JSON Classes to parse XML or JSON content in the body of a request created by HttpRequest. PUT. For example: • DELETE • GET • HEAD • POST • PUT • TRACE getEndpoint getHeader getMethod 510 .Reference HTTP (RESTful) Services Classes Use the DOM Classes or JSON Classes to parse XML or JSON content in the body of a request created by HttpRequest. false otherwise. or a response accessed by HttpResponse. String Returns a string that displays and identifies the object's properties. Http Class Use the Http class to initiate an HTTP request and response. the request body is compressed. The Http class contains the following public methods: Name send Arguments HttpRequest request Return Type Description System. POST. Use it as a shortcut for: String xml = httpRequest.HttpResponse Sends an HttpRequest and returns the response.getBody().Document(xml). Retrieves the URL for the endpoint of the external server for this request. Retrieves the body of this request as a Blob. document. Dom.Document domDoc = new Dom. The HttpRequest class contains the following public methods: Name getBody getBodyAsBlob getBodyDocument Arguments Return Type String Blob Description Retrieves the body of this request. and DELETE. Returns the type of method used by HttpRequest.Document Retrieves the body of this request as a DOM getCompressed Boolean String String key String String If true. Sets the URL for the endpoint of the external server for this request. Limit: 3 MB. setClientCertificateName String certDevName Void If the external service requires a client certificate for authentication.000 milliseconds. Sets the type of method to be used for the HTTP request. 511 .Reference HTTP (RESTful) Services Classes Name setBody Arguments String body Return Type Void Description Sets the contents of the body for this request. Use setClientCertificateName instead. the data in the body is delivered to the endpoint in the gzip compressed format. Limit 100 KB. See Using Certificates with HTTP Requests. If true. The HTTP request and response sizes count towards the total heap size. setBodyDocument Dom. set the certificate name. This method is deprecated. For example: • DELETE • GET • HEAD • POST • PUT • TRACE You can also use this method to set any required options. setClientCertificate String clientCert String password If the server requires a client certificate for authentication.Document document Void Void Sets the contents of the body for this request. If false. The contents represent a DOM document. This can be any value between 1 and 60. no compression format is used. setCompressed Boolean flag Void setEndpoint String endpoint String key String Value Void Void setHeader setMethod String method setTimeout Integer timeout Void Sets the timeout in milliseconds for the request. setBodyAsBlob Blob body Void Sets the contents of the body for this request using a Blob. Limit: 3 MB. Limit: 3 MB. The HTTP request and response sizes count towards the total heap size. Sets the contents of the request header. set the client certificate PKCS12 key store and password. debug(res. } } Compression If you need to compress the data you send. getBody automatically recognizes the format. System. as the following sample illustrates: HttpRequest req = new HttpRequest().setMethod('GET'). The HttpResponse class contains the following public methods: 512 . req. uncompresses it. use setCompressed. and returns the uncompressed value.setCompressed(true). authorizationHeader).getBody()). HTTPResponse res = http. Endpoint=http://YourServer. // Create a new http object to send the request object // A response object is generated as a result of the request Http http = new Http().setEndPoint('my_endpoint'). Blob headerValue = Blob. req. String password = 'mypwd'. String authorizationHeader = 'BASIC ' + EncodingUtil. // Specify the required user name and password to access the endpoint // As well as the header and header information String username = 'myname'.setEndpoint('http://www. req.base64Encode(headerValue).com'). HttpResponse Class Use the HttpResponse class to handle the HTTP response returned by the Http class. Method=POST The following example illustrates how you can use an authorization header with a request.Reference HTTP (RESTful) Services Classes Name toString Arguments Return Type String Description Returns a string containing the URL for the endpoint of the external server for this request and the method used.setHeader('Authorization'.valueOf(username + ':' + password). req.setBody('some post body'). for example.send(req). If a response comes back in compressed format. Use the DOM Classes or JSON Classes to parse XML or JSON content in the body of a response accessed by HttpResponse. req.yahoo. and handle the response: public class AuthCallout { public void basicAuthCallout(){ HttpRequest req = new HttpRequest(). req. The HTTP request and response sizes count towards the total heap size.Document Retrieves the body returned in the response as a DOM document. The HTTP request and response sizes count towards the total heap size. Specifies the body returned in the response using a Blob. getBodyAsBlob Blob Retrieves the body returned in the response as a Blob. Retrieves an array of header keys returned in the response. Specifies the contents of the response header. Void String value setStatus setStatusCode toString String Integer Void Void String Specifies the status message returned in the response.Document(xml). XmlStreamReader xsr = new XmlStreamReader(xml). getBodyDocument Dom. For a full example. Specifies the value of the status code returned in the response. Returns an XmlStreamReader (XmlStreamReader Class) that parses the body of the callout response. Use it as a shortcut for: String xml = httpResponse. Dom. Returns the status message and status code returned in the response. Retrieves the status message returned for the response.getBody().Document domDoc = new Dom. for example: Status=OK.Reference HTTP (RESTful) Services Classes Name getBody Arguments Return Type String Description Retrieves the body returned in the response. setBody setBodyAsBlob setHeader String Blob Void Void Specifies the body returned in the response. getHeader getHeaderKeys getStatus getStatusCode getXmlStreamReader String key String String[] String Integer XmlStreamReader Retrieves the contents of the response header. see getXmlStreamReader example. Use it as a shortcut for: String xml = httpResponse. StatusCode=200 513 . Retrieves the value of the status code returned in the response. Limit3 MB. String key. Limit3 MB.getBody(). test methods don’t support HTTP callouts and tests that perform callouts are skipped. } } Note: • • The class that implements the HttpCalloutMock interface can be either global or public. HttpResponse res = http. // Generate the HTTP response as an XML stream XmlStreamReader reader = res.debug(reader. you can exclude it from your organization’s code size limit of 3 MB. req.getXmlStreamReader(). // Set response values. which the Apex runtime calls to send a response for a callout. } } } Testing HTTP Callouts To deploy or package Apex. if (reader.setMock and by specifying the mock response in one of the following ways: • • By implementing the HttpCalloutMock interface By using Static Resources with StaticResourceCalloutMock or MultiStaticResourceCalloutMock Testing HTTP Callouts by Implementing the HttpCalloutMock Interface Provide an implementation for the HttpCalloutMock interface to specify the response sent in the respond method. and // return response.xml').debug('Event Type:' + reader. 514 . By default. // Log the XML content System.send(req). In this way. req.hasNext()) { System.setEndpoint('http://www. You can annotate this class with @isTest since it will be used only in test context.debug(res.getBody()). public class ReaderFromCalloutSample { public void getAndParse() { // Get the XML document from the external server Http http = new Http().START_ELEMENT) { System.com/tutorial/sample1/build. However. 75% of your code must have test coverage.getLocalName()).getEventType()). // Read through the XML while(reader.getEventType() == XmlTag. } reader. you can enable HTTP callout testing by instructing Apex to generate mock responses in tests by calling Test.next().cheenath. global class YourHttpCalloutMockImpl implements HttpCalloutMock { global HTTPResponse respond(HTTPRequest req) { // Create a fake response. HttpRequest req = new HttpRequest().setMethod('GET'). then the XML is parsed using the XmlStreamReader class. content is retrieved from an external Web server.Reference HTTP (RESTful) Services Classes In the following getXmlStreamReader example. com/foo/bar').class.setBody('{"foo":"bar"}').setMock from a test method in the same package with the same namespace to mock the callout. you must call Test. and for the second argument. the callout is not made and you receive the mock response you specified in the respond method implementation.setStatusCode(200). } } @isTest private class CalloutClassTest { @isTest static void testCallout() { // Set mock callout class Test. For the first argument. Http h = new Http(). res. HttpResponse res = h.setEndpoint('http://api. // This causes a fake response to be sent // from the class that implements HttpCalloutMock. Save each class separately and run the test in CalloutClassTest.Reference HTTP (RESTful) Services Classes Now that you have specified the values of the fake response. The testCallout test method sets the mock callout mode by calling Test. // Create a fake response HttpResponse res = new HttpResponse().assert(contentType == 'application/json'). res.getMethod()). return res.salesforce.setMock(HttpCalloutMock.class. HttpResponse res = CalloutClass.assertEquals('GET'.com/foo/bar'. pass a new instance of your interface implementation of HttpCalloutMock. This is a full example that shows how to test an HTTP callout.setMock(HttpCalloutMock. req. req. res. req.getHeader('Content-Type'). The interface implementation (MockHttpResponseGenerator) is listed first. instruct the Apex runtime to send this fake response by calling Test. 'application/json').salesforce. It is followed by a class containing the test method and another containing the method that the test calls. It then verifies that the response returned is what the implemented respond method sent. if an HTTP callout is invoked in test context. 515 . Note: If the code that performs the callout is in a managed package.setMock before calling getInfoFromExternalService.getInfoFromExternalService(). @isTest global class MockHttpResponseGenerator implements HttpCalloutMock { // Implement this interface method global HTTPResponse respond(HTTPRequest req) { // Optionally. only send a mock response for a specific endpoint // and method. as follows: Test. req.send(req). After this point. System.getEndpoint()). return res. } } public class CalloutClass { public static HttpResponse getInfoFromExternalService() { HttpRequest req = new HttpRequest().class.setMethod('GET'). // Verify response received contains fake values String contentType = res.setHeader('Content-Type'.setMock in your test method.assertEquals('http://api. pass HttpCalloutMock. System. new YourHttpCalloutMockImpl()). System. // Call method to test. new MockHttpResponseGenerator()). create an instance of StaticResourceCalloutMock and set the static resource. When using this class. To learn more about static resources. d. b. and then New Static Resource. but it must match the content type. the callout is not made and the Apex runtime sends the mock response you specified in your instance of StaticResourceCalloutMock. if your test method performs a callout. mock. if specified. expectedValue). After this point. Create a text file that contains the response body to return. System. and the variable name that you created for StaticResourceCalloutMock as the second argument. If you specify a content type of application/json for the response. c.assertEquals(actualValue. such as {"hah":"fooled you"}.Reference HTTP (RESTful) Services Classes String actualValue = res. just create an instance of StaticResourceCalloutMock and set the static resource to use for the response body. For example. Test. call Test. mock). Create a static resource for the text file: a.class as the first argument. Choose the file to upload.class. see “Defining Static Resources” in the Salesforce online help. and any other properties.setMock(HttpCalloutMock. along with other response properties. like the status code and content type. StaticResourceCalloutMock mock = new StaticResourceCalloutMock(). String expectedValue = '{"foo":"bar"}'.setStaticResource('myStaticResourceName').getBody(). the file can include the arbitrary string abc. you must create a static resource from a text file to contain the response body: 1. the file content should be a JSON string. mock. 'application/json').assertEquals(200. The response body can be an arbitrary string.getStatusCode()). Click Your Name > Setup > Develop > Static Resources.setHeader('Content-Type'. you don’t have to provide your own implementation of the HttpCalloutMock interface. System.setStatusCode(200). Testing HTTP Callouts Using StaticResourceCalloutMock Apex provides the built-in StaticResourceCalloutMock class that you can use to test callouts by specifying the response body in a static resource. res. Instead. Name your static resource. Next. mock.setMock to set the mock callout mode and pass it HttpCalloutMock. In your test method. if your response has no content type specified. First. 2. } } See Also: Testing HTTP Callouts Using Static Resources HttpCalloutMock Interface Testing HTTP Callouts Using Static Resources You can test HTTP callouts by specifying the body of the response you’d like to receive in a static resource and using one of two built-in classes—StaticResourceCalloutMock or MultiStaticResourceCalloutMock. 516 . Click Save. You can also set other response properties like the status code and content type. } } Testing HTTP Callouts Using MultiStaticResourceCalloutMock Apex provides the built-in MultiStaticResourceCalloutMock class that you can use to test callouts by specifying the response body in a static resource for each endpoint.assertEquals('{"hah":"fooled you"}'. public class CalloutStaticClass { public static HttpResponse getInfoFromExternalService(String endpoint) { HttpRequest req = new HttpRequest(). create an instance of MultiStaticResourceCalloutMock and set the static resource. you must create a static resource from a text file to contain the response body. } } @isTest private class CalloutStaticClassTest { @isTest static void testCalloutWithStaticResources() { // Use StaticResourceCalloutMock built-in class to // specify fake response and include response body // in a static resource.com/foo/bar'. Save each class separately and run the test in CalloutStaticClassTest. This class is similar to StaticResourceCalloutMock except that it allows you to specify multiple response bodies. StaticResourceCalloutMock mock = new StaticResourceCalloutMock(). mock). return res.Reference HTTP (RESTful) Services Classes Note: If the code that performs the callout is in a managed package. req. HttpResponse res = h. Before running this example.setMock(HttpCalloutMock.class. System.getInfoFromExternalService( 'http://api.setStaticResource('mockResponse'). // Set the mock callout mode Test. just create an instance of MultiStaticResourceCalloutMock and set the static resource to use per endpoint.setHeader('Content-Type'. mock.assertEquals('application/json'. System. res.send(req).res.getBody()).com/foo/bar').setMock from a test method in the same package with the same namespace to mock the callout. you must call Test. MultiStaticResourceCalloutMock multimock = new MultiStaticResourceCalloutMock(). // Call the method that performs the callout HTTPResponse res = CalloutStaticClass. Next. 'application/json'). 'mockResponse'). mock. mock. First. create a static resource named mockResponse based on a text file with the content {"hah":"fooled you"}.salesforce. res. See the procedure outlined in Testing HTTP Callouts Using StaticResourceCalloutMock.getStatusCode()). // Verify response received contains values returned by // the mock response. and any other properties.setStatusCode(200). req.salesforce. multimock. // This is the content of the static resource.setEndpoint(endpoint). When using this class.setStaticResource('http://api.getHeader('Content-Type')). This is a full example containing the test method (testCalloutWithStaticResources) and the method it is testing (getInfoFromExternalService) that performs the callout.assertEquals(200. 517 . System. Instead.setMethod('GET'). Http h = new Http(). you don’t have to provide your own implementation of the HttpCalloutMock interface. getInfoFromExternalService( 'http://api.setStatusCode(200).com/foo/bar or http://api. multimock). res. multimock).setMock(HttpCalloutMock.assertEquals('{"hah":"fooled you"}'. This is a full example containing the test method (testCalloutWithMultipleStaticResources) and the method it is testing (getInfoFromExternalService) that performs the callout. In your test method.setMock to set the mock callout mode and pass it HttpCalloutMock. public class CalloutMultiStaticClass { public static HttpResponse getInfoFromExternalService(String endpoint) { HttpRequest req = new HttpRequest().com/foo/bar').setStatusCode(200). multimock. multimock.send(req).salesforce.salesforce.com/foo/bar'.setHeader('Content-Type'. HttpResponse res = h. 'mockResponse2').setStaticResource( 'http://api.com/foo/sfdc'). Test.Reference HTTP (RESTful) Services Classes multimock.setStaticResource( 'http://api.salesforce. 'application/json').salesforce. multimock.setMethod('GET'). After this point.assertEquals('{"hah":"fooled you twice"}'.class. Before running this example. the callout is not made and the Apex runtime sends the corresponding mock response you specified in your instance of MultiStaticResourceCalloutMock. Save each class separately and run the test in CalloutMultiStaticClassTest. multimock. 'application/json'). req.salesforce.setStaticResource('http://api. multimock. if your test method performs an HTTP callout to one of the endpoints http://api. // Verify response received System.setMock(HttpCalloutMock. // Set the mock callout mode Test. 'mockResponse'). 'mockResponse2'). MultiStaticResourceCalloutMock multimock = new MultiStaticResourceCalloutMock().setEndpoint(endpoint).getInfoFromExternalService( 'http://api. Http h = new Http().salesforce. // Call the method for the second endpoint HTTPResponse res2 = CalloutMultiStaticClass. res2. } } @isTest private class CalloutMultiStaticClassTest { @isTest static void testCalloutWithMultipleStaticResources() { // Use MultiStaticResourceCalloutMock to // specify fake response for a certain endpoint and // include response body in a static resource. req.setHeader('Content-Type'. return res. create a static resource named mockResponse based on a text file with the content {"hah":"fooled you"} and another named mockResponse2 based on a text file with the content {"hah":"fooled you twice"}. // Call the method for the first endpoint HTTPResponse res = CalloutMultiStaticClass. 518 .salesforce.getBody()).class as the first argument. multimock. // Verify response received System.getBody()).com/foo/sfdc.class. call Test.com/foo/sfdc'. and the variable name that you created for MultiStaticResourceCalloutMock as the second argument.com/foo/sfdc'. and signatures. The length of privateKey must match the specified algorithm: 128 bits. as well as encrypting and decrypting information. Valid values for algorithmName are: 519 . 24. Use this method to decrypt blobs encrypted using a third party application or the encryptWithManagedIV method. Use this method to decrypt blobs encrypted using a third party application or the encrypt method. or 32 bytes. These can be used for securing content in Force. Name decrypt Arguments String algorithmName Return Type Description Blob Decrypts the blob cipherText using the specified algorithm. or 256 bits.Reference HTTP (RESTful) Services Classes } } See Also: Testing HTTP Callouts by Implementing the HttpCalloutMock Interface MultiStaticResourceCalloutMock Methods StaticResourceCalloutMock Methods Crypto Class The methods in the Crypto class provide standard algorithms for creating digests. You can use a third-party application or the generateAesKey method to generate this key for you. 192 bits. respectively. They use cipher block chaining (CBC) and PKCS5 padding. For more information about possible exceptions thrown during execution. or for integrating with external services such as Google or Amazon WebServices (AWS).com. The initialization vector must be 128 bits (16 bytes. Valid values for algorithmName are: • • • AES128 AES192 AES256 Blob privateKey Blob initializationVector Blob cipherText These are all industry standard Advanced Encryption Standard (AES) algorithms with different size keys. and initialization vector. see Encrypt and Decrypt Exceptions. which is 16. decryptWithManagedIV String algorithmName Blob Blob privateKey Decrypts the blob IVAndCipherText using the specified algorithm and private key. private key.) For an example. message authentication codes. see Example Encrypting and Decrypting. private key and initialization vector.Reference HTTP (RESTful) Services Classes Name Arguments Blob IVAndCipherText Return Type Description • • • AES128 AES192 AES256 These are all industry standard Advanced Encryption Standard (AES) algorithms with different size keys.) Use either a third-party application or the decrypt method to decrypt blobs encrypted using this method. which is 16. respectively. 192 bits. The length of privateKey must match the specified algorithm: 128 bits. or 256 bits. For more information about possible exceptions thrown during execution. The initialization vector must be 128 bits (16 bytes. You can use a third-party application or the generateAesKey method to generate this key for you. Valid values for algorithmName are: • • • AES128 AES192 AES256 These are all industry standard Advanced Encryption Standard (AES) algorithms with different size keys. or 256 bits. encrypt String algorithmName Blob Blob privateKey Blob initializationVector Blob clearText Encrypts the blob clearText using the specified algorithm. which is 16. 24. respectively. 192 bits. They use cipher block chaining (CBC) and PKCS5 padding. see Example Encrypting and Decrypting. The length of privateKey must match the specified algorithm: 128 bits. see Example Encrypting and Decrypting. or 32 bytes. Use the encryptWithManagedIV method if you want Salesforce to generate the initialization vector for you. Use this method when you want to specify your own initialization vector. For an example. It is stored as the first 128 bits (16 bytes) of the encrypted blob. or 32 bytes. You can use a third-party application or the generateAesKey method to generate this key for you. 24. The first 128 bits (16 bytes) of IVAndCipherText must contain the initialization vector. 520 . For an example. see Encrypt and Decrypt Exceptions. They use cipher block chaining (CBC) and PKCS5 padding. For more information about possible exceptions thrown during execution. encryptWithManagedIV String algorithmName Blob Blob privateKey Blob clearText Encrypts the blob clearText using the specified algorithm and private key. They use cipher block chaining (CBC) and PKCS5 padding. see Encrypt and Decrypt Exceptions. 24. 192 bits. You can use a third-party application or the generateAesKey method to generate this key for you. Use this method when you want Salesforce to generate the initialization vector for you. For an example. It is stored as the first 128 bits (16 bytes) of the encrypted blob.Reference HTTP (RESTful) Services Classes Name Arguments Return Type Description For more information about possible exceptions thrown during execution. see Example Encrypting and Decrypting. or 32 bytes. one-way hash digest based on the supplied input string and algorithm name. Valid values for algorithmName are: • MD5 • SHA1 • SHA-256 • SHA-512 generateDigest String algorithmName Blob Blob input 521 . Use either third-party applications or the decryptWithManagedIV method to decrypt blobs encrypted with this method. Use size to specify the key's size in bits. or 256 bits. Valid values are: • 128 • 192 • 256 Computes a secure. The length of privateKey must match the specified algorithm: 128 bits. respectively. Use the encrypt method if you want to generate your own initialization vector. which is 16. generateAesKey Integer size Blob Generates an Advanced Encryption Standard (AES) key. Valid values for algorithmName are: • • • AES128 AES192 AES256 These are all industry standard Advanced Encryption Standard (AES) algorithms with different size keys. see Encrypt and Decrypt Exceptions. using the private key and the specified algorithm.base64Decode(key). String timestamp = ''+ d.hour() + ':' + d.sign(algorithmName. String key = 'pkcs8 format private key'. Blob privateKey = EncodingUtil. Returns a random Long.day() + '\'T\'' + d. The value cannot exceed 4 KB. input. Both values represent the same algorithm.valueOf('12345qwerty').SSS'Z' DateTime d = System. The following snippet is an example declaration and initialization: String algorithmName = 'RSA'.minute() + ':' + 522 .Reference HTTP (RESTful) Services Classes Name generateMac Arguments String algorithmName Return Type Description Blob Computes a message authentication code (MAC) for the input string. The value of privateKey must be decoded using the EncodingUtil base64Decode method. Blob input Blob privateKey getRandomInteger getRandomLong sign Integer Long String algorithmName Returns a random Integer. privateKey). using the supplied private key and the specified algorithm. The value cannot exceed 4 KB. Computes a unique digital signature for the input string.month() + '-' + d. The valid values for algorithmName are RSA-SHA1 or RSA.2) Private-Key Information Syntax Standard form. and should be in RSA's PKCS #8 (1. Blob Blob input Blob privateKey Example Integrating Amazon WebServices The following example demonstrates an integration of Amazon WebServices with Salesforce: public class HMacAuthCallout { public void testAlexaWSForAmazon() { // The date format is yyyy-MM-dd'T'HH:mm:ss. Blob input = Blob.year() + '-' + d. Crypto.now(). The valid values for algorithmName are: • hmacMD5 • hmacSHA1 • hmacSHA256 • hmacSHA512 The value of privateKey does not need to be in decoded form. // Decrypt the data Blob decryptedData = Crypto.' + d.base64Encode(mac). HttpRequest req = new HttpRequest(). System. encryptedData). // Use generateAesKey to generate the private key Blob cryptoKey = Crypto.debug('ERROR: '+ e).debug('STATUS:'+res. String urlEncodedTimestamp = EncodingUtil. String macUrl = EncodingUtil. String timeFormat = d. Blob. Blob data = Blob.getBody()). // Generate the data to be encrypted.amazonaws.urlEncode(timestamp. 523 .com/'. 'UTF-8'). Blob.send(req). System. The following is an example of writing a unit test for the encryptWithManagedIV and decryptWithManagedIV methods. String algorithmName = 'HMacSHA1'.setEndpoint(endpoint + '?AWSAccessKeyId=' + accessKey + '&Action=' + action + '&ResponseGroup=Rank&Version=' + version + '&Timestamp=' + urlEncodedTimestamp + '&Url=' + urlToTest + '&Signature=' + macUrl).com generate the initialization vector Blob encryptedData = Crypto.debug('BODY: '+res.CalloutException e) { System. // Encrypt the data and have Salesforce. String action = 'UrlInfo'. as well as the generateAesKey method.generateAesKey(256). String String String String urlToTest = 'amazon.com'. 'UTF-8'). String inputStr = action + timeFormat. } } } Example Encrypting and Decrypting The following example uses the encryptWithManagedIV and decryptWithManagedIV methods. @isTest private class CryptoTest { public static testMethod void testValidDecryption() { // Use generateAesKey to generate the private key Blob key = Crypto.decryptWithManagedIV('AES256'. Http http = new Http().millisecond() + '\'Z\''. } catch(System. accessKey = 'your_key'.getStatus()).second() + '.urlEncode(EncodingUtil.valueOf(inputStr). System.setMethod('GET'). try { HttpResponse res = http.Reference HTTP (RESTful) Services Classes d.encryptWithManagedIV('AES256'.valueOf('your_signing_key')).debug('STATUS_CODE:'+res. data). req.valueOf('Test data to encrypted'). cryptoKey.generateMac(algorithmName. endpoint = 'http://awis.formatGmt(timestamp). Blob mac = Crypto.getStatusCode()).generateAesKey(128). version = '2005-07-11'. cryptoKey. req. valueOf('Test data').generateAesKey(256). // Generate the data to be encrypted. Thrown if size of the private key doesn't match the specified algorithm. } } } Encrypt and Decrypt Exceptions The following exceptions can be thrown for these methods: • • • • decrypt encrypt decryptWithManagedIV encryptWithManagedIV Exception InvalidParameterValue Message Description Unable to parse initialization vector from Thrown if you're using managed encrypted data. Argument cannot be null.assert(false).decryptWithManagedIV('AES256'. e. b64Decrypted). key.assertEquals('Given final block not properly padded'. Blob decryptedData = Crypto. AES192.getMessage()). Thrown if one of the required method arguments is null.encryptWithManagedIV('AES128'. encryptedData). data).Reference HTTP (RESTful) Services Classes // Generate the data to be encrypted. // Generate an encrypted form of the data using base64 encoding String b64Data = EncodingUtil. Invalid data. System. which exceeds the limit of 1048576 bytes. Must be AES128. Blob data = Blob. key.encryptWithManagedIV('AES128'.base64Encode(decryptedData). encryptedData). using different key sizes Blob keyOne = Crypto. Invalid algorithm algoName. initialization vectors. } catch(SecurityException e) { System. Input data is size bytes. Thrown if the data is greater than 1 MB. data). 1048608 bytes are allowed for the initialization vector header.base64Encode(data). Thrown if the algorithm name isn't one of the valid values. Blob data = Blob. String b64Decrypted = EncodingUtil.generateAesKey(128).valueOf('Test data').decryptWithManagedIV('AES128'. keyOne. or AES256. NullPointerException 524 . Invalid initialization vector. For decryption. 16 bytes. // Encrypt the data using the first key Blob encryptedData = Crypto. } public static testMethod void testInvalidDecryption() { // Verify that you must use the same key size for encrypting data // Generate two private keys. try { // Try decrypting the data using the second key Crypto. plus any additional padding the encryption added to align to block size. Must be size bytes. // Encrypt and decrypt the data Blob encryptedData = Crypto. // Verify that the strings still match System. Blob keyTwo = Crypto. keyTwo. and the cipher text is less than 16 bytes. Must be 16 Thrown if the initialization vector isn't bytes.assertEquals(b64Data. InvalidParameterValue InvalidParameterValue InvalidParameterValue InvalidParameterValue Invalid private key. Description Thrown if the data isn't properly block-aligned or similar issues occur during encryption or decryption. however.urlEncode(url. To do so. Encodes a string into the application/x-www-form-urlencoded format using a String inputString Blob Blob inputBlob Blob inputString String String base64Encode convertToHex urlDecode String inputString String String encodingScheme urlEncode String inputString String String encodingScheme specific encoding scheme. Thrown if something goes wrong during either encryption or decryption. see The form-urlencoded Media Type in Hypertext Markup Language 2. Converts a Blob to an unencoded String representing its normal form. 'UTF-8'). For more information about the format. see The form-urlencoded Media Type in Hypertext Markup Language . query the ID of the document using the API query call. for example “UTF-8. This method can be used to compute the client response (for example.0. Returns a hexadecimal (base 16) representation of the inputString.” This method uses the supplied encoding scheme to obtain the bytes for unsafe characters. Note: You cannot use the EncodingUtil methods to move documents with non-ASCII characters to Salesforce. Decodes a string in application/x-www-form-urlencoded format using a specific encoding scheme.Reference HTTP (RESTful) Services Classes Exception SecurityException Message Given final block not properly padded. You can. SecurityException Message Varies EncodingUtil Class Use the methods in the EncodingUtil class to encode and decode URL strings.0. Example: String encoded = EncodingUtil. 525 . Name base64Decode Arguments Return Type Description Converts a Base64-encoded String to a Blob representing its normal form. and convert strings to hexadecimal format.” This method uses the supplied encoding scheme to determine which characters are represented by any consecutive sequence of the from \"%xy\". then request it by ID. for example “UTF-8.2. download a document from Salesforce. HA1 or HA2) for HTTP Digest Authentication (RFC2617). For more information about the format. An entity reference is an entity reference in the code.com for Dummies">. A start element event is the opening tag for an element.generateDigest('SHA1'. These methods work on the following XML events: • • • • • • • • An attribute event is specified for a particular element. XmlStreamReader xsr = new XmlStreamReader(xmlString). for example !ENTITY title = "My Book Title". A comment event is a comment in the XML file. • • XmlStreamReader Class XmlStreamWriter Class XmlStreamReader Class Similar to the XMLStreamReader utility class from StAX. System. String hexDigest = EncodingUtil.convertToHex(hash). methods in the XmlStreamReader class enable forward. For example. Blob hash = Crypto. read-only access to XML data. An end element event is the closing tag for an element.Reference XML Classes The following example illustrates how to use convertToHex to compute a client response for HTTP Digest Authentication (RFC2617): global class SampleCode { static testmethod void testConvertToHex() { String myData = 'A Test String'. An end document event is the closing tag for a document. A characters event is a text character. The following code snippet illustrates how to instantiate a new XmlStreamReader object: String xmlString = '<books><book>My Book</book><book>Your Book</book></books>'.valueOf(myData)). A start document event is the opening tag for a document. the element <book> has an attribute title: <book title="Salesforce.debug(hexDigest). Access data in XML using get methods such as the getNamespace method. for example <book>. You can pull data from XML or skip unwanted events.Blob. for example </book>. } } XML Classes Use the following classes to read and write XML content: • • XmlStream Classes DOM Classes XmlStream Classes Use the XmlStream methods to read and write XML strings. 526 . Use the next and hasNext methods to iterate over XML data. This method is only valid with start element or attribute XML events. For example. If no namespace is specified. This value excludes namespace definitions. You must specify a value for localName. This method is only valid on a start element or attribute XML events. The count for the number of attributes for an attribute XML event starts with zero. null is returned. The following methods are available to support reading XML files: Name getAttributeCount Arguments Return Type Integer Description Returns the number of attributes on the start element. Returns null if the value is not found. See java.stream. This method is only valid with start element or attribute XML events. Returns the namespace URI of the attribute at the specified index. Returns the value of the attribute in the specified localName at the specified URI. Returns the value of the attribute at the specified index. If no prefix is specified. If there is no name. XmlTag is an enumeration of constants indicating the type of XML event the cursor is pointing to: • ATTRIBUTE • CDATA • CHARACTERS • COMMENT • DTD • END_DOCUMENT • END_ELEMENT • ENTITY_DECLARATION getAttributeLocalName Integer index String getAttributeNamespace Integer index String getAttributePrefix Integer index String getAttributeType Integer index String getAttributeValue String namespaceURI String String localName getAttributeValueAt Integer index String getEventType System. Returns the local name of the attribute at the specified index.XmlTag 527 .xml. Returns the prefix of this attribute at the specified index. This method is only valid with start element or attribute XML events. null is returned. id is an attribute type. an empty string is returned.XMLStreamReader.Reference XML Classes Note: The XmlStreamReader class in Apex is based on its counterpart in Java. This method is only valid with start element or attribute XML events. This method is only valid with start element or attribute XML events. This method is only valid with start element or attribute XML events. Returns the XML type of the attribute at the specified index. The returned URI depends on the current state of the processor. this method returns the URI of the prefix or the default namespace. This method is only valid on a start element. For start element or end element XML events.Reference XML Classes Name Arguments Return Type Description • • • • • • • ENTITY_REFERENCE NAMESPACE NOTATION_DECLARATION PROCESSING_INSTRUCTION SPACE START_DOCUMENT START_ELEMENT getLocalName String Returns the local name of the current event. Returns the number of namespaces declared on a start element or end element. Returns the prefix of the current XML event or null if the event does not have a prefix. If the current event is a start element or end element. Returns null if this is the default namespace declaration. end element. or namespace XML event. If the location is unknown. This method is only valid on a start element. Returns the URI for the namespace declared at the index. Return the current location of the cursor. end element. end element. it returns the local name of the current element. Returns null if the XML event does not have a prefix. or entity reference. The valid values for the different events are: • The string value of a character XML event • The string value of a comment getLocation String getNamespace String getNamespaceCount Integer getNamespacePrefix Integer index String getNamespaceURI String Prefix String String getNamespaceURIAt Integer Index getPIData getPITarget getPrefix String String String String getText 528 . For the entity reference XML event. Returns the current value of the XML event as a string. returns -1. or namespace XML event. The location information is only valid until the next method is called. or namespace XML event. This method is only valid on a start element. Returns the prefix for the namespace declared at the index. Returns the target section of a processing instruction. end element. The current XML event must be start element. it returns the entity name. Return the URI for the given prefix. Returns the data section of a processing instruction. </foo>'. Returns true if the cursor points to a character data XML event. For example. Returns null if none was declared. until a start element or end element is reached.Reference XML Classes Name Arguments Return Type Description • The replacement value for an entity reference. Returns false otherwise. Returns true if the current XML event has a name. Returns an integer which indicates the type of event. Returns true if there are more XML events and false if there are no more XML events. Otherwise. it returns false. returns false. comment and space. This hasName hasNext Boolean hasText Boolean isCharacters Boolean Boolean Boolean Boolean isEndElement isStartElement isWhiteSpace next Integer nextTag Integer 529 . Otherwise. Otherwise. or processing instruction XML events. • • • getVersion The getText method returns Salesforce for Dummies. The string value of a CDATA section The string value for a space XML event The string value of the internal subset of the DTD String Boolean Returns the XML version specified on the XML declaration. assume getText reads the following XML snippet: <!ENTITY Title "Salesforce For Dummies" > ]> <foo a=\"b\">Name &Title. or it may split it into several chunks. entity reference. it returns false. This method returns false if the current XML event is end document. false otherwise The following XML events have text: characters. Skips any white space (the isWhiteSpace method returns true). comment. Returns true if the current event has text. Returns true if the cursor points to a character data XML event that consists of all white space. Returns true if the cursor points to an end tag. This method is only valid for start element and stop element XML events. not &Title. A processor may return all contiguous character data in a single chunk. Otherwise it returns false. Returns true if the cursor points to a start tag. Reads the next XML event. Returns the index for that XML event. Returns a string containing the length of the input XML given to XmlStreamReader and the first 50 characters of the input XML. public class XmlStreamReaderDemo { // Create a class Book for processing public class Book { String name. } return books. If you specify it as false. the parser may return text in multiple blocks. } reader. comments. the parser recognizes namespace. text is returned in a single block. start elements or stop elements are encountered.END_ELEMENT) { break.getEventType() == XmlTag. setNamespaceAware Boolean Void isNamespaceAware toString String XmlStreamReader Example The following example processes an XML string.next().add(book). } else if (reader.getLocalName()) { // Pass the book to the parseBook method (below) Book book = parseBook(reader). processing instruction. The default value is true. String author. book.CHARACTERS) { book. while(reader. 530 . If you specify true for isNamespaceAware.name = reader.getEventType() == XmlTag. If you specify it as false. whichever comes first.author = reader.next().getAttributeValue(null.getText(). setCoalescing Boolean returnAsSingleBlock Void If you specify true for returnAsSingleBlock.getEventType() == XmlTag. } // Parse through the XML. the parser does not. } } reader. } Book[] parseBooks(XmlStreamReader reader) { Book[] books = new Book[0]. 'author'). while(reader.START_ELEMENT) { if ('Book' == reader.Reference XML Classes Name Arguments Return Type Description method throws an error if elements other than white space. from a start element to the first end element or the next start element. determine the author and the characters Book parseBook(XmlStreamReader reader) { Book book = new Book(). books.hasNext()) { // Start at the beginning of the book and make sure that it is a book if (reader.hasNext()) { if (reader. Reference XML Classes } return book. Binds the specified URI to the default namespace.html.size()). Book[] books = demo. See https://stax-utils. you can use the XmlStreamWriter class to programmatically construct an XML document. localName specifies the name of the attribute.debug(book). String str = '<books><book author="Chatty">Foo bar</book>' + '<book author="Sassy">Baz</book></books>'. Note: The XmlStreamWriter class in Apex is based on its counterpart in Java.dev. System.java. 531 . Returns the XML written by the XmlStreamWriter instance. } // Test that the XML string contains specific values static testMethod void testBookParser() { XmlStreamReaderDemo demo = new XmlStreamReaderDemo(). methods in the XmlStreamWriter class enable the writing of XML data. The following code snippet illustrates how to instantiate a new XmlStreamWriter: XmlStreamWriter w = new XmlStreamWriter(). then use HTTP Classes to send the document to an external server. getXmlString setDefaultNamespace String URI Void writeAttribute String prefix String namespaceURI String localName String value Void writeCData String data Void Writes the specified CData to the output stream. for (Book book : books) { System.parseBooks(reader).net/nonav/javadoc/api/javax/xml/stream/XMLStreamWriter. The following methods are available to support writing XML files: Name close Arguments Return Type Description Void String Closes this instance of an XmlStreamWriter and free any resources associated with it. Writes an attribute to the output stream. XmlStreamReader reader = new XmlStreamReader(str). } } } XmlStreamWriter Class Similar to the XMLStreamWriter utility class from StAX. For example.debug(books. This URI is bound in the scope of the current START_ELEMENT – END_ELEMENT pair. writeDefaultNamespace String namespaceURI writeEmptyElement String prefix String localName String namespaceURI writeEndDocument Void Void Closes any start tags and writes corresponding end tags to the output stream. Writes the specified comment to the output stream.writeCData('<Cdata> I like CData </Cdata>'). w. see wiki. Writes the specified namespace to the output stream. Writes an empty element tag to the output stream.com AppExchange.writeStartElement('m'. 'Library'.com'). 'book'.com'). fields and Apex code as a managed packaged from Force. w.setDefaultNamespace('http://www. writeStartElement String prefix String localName String namespaceURI Void XML Writer Methods Example The following example writes an XML document and tests its validity.developerforce.defns. String data writeStartDocument String encoding String version Void Writes the XML Declaration using the specified XML encoding and version.com'). w. w.book.0'). localName specifies the name of the tag to be written. Writes an end tag to the output stream.com/index.book. writeEndElement writeNamespace String prefix String namespaceURI Void writeProcessingInstruction String target Void Writes the specified processing instruction. public class XmlWriterDemo { public String getXml() { XmlStreamWriter w = new XmlStreamWriter(). 'data'). 'http://www. or download the objects. 'http://www.writeComment('Book starts here'). w. w. Writes the start tag specified by localName to the output stream. w. Note: The Hello World and the shipping invoice samples require custom fields and objects.php/Documentation.writeProcessingInstruction('target'.writeNamespace('m'. Writes the specified namespace to the output stream. For more information. null). '1. w.writeStartDocument(null.writedefaultNamespace('http://www. 532 . w.com'). You can either create these on your own.defns.writeStartElement(null.Reference XML Classes Name writeCharacters writeComment Arguments String text String data Return Type Description Void Void Void Void Writes the specified text to the output stream. relying on the internal state of the writer to determine the prefix and local name. w. //end book w.name. Document Class Use the Document class to process XML content. } } DOM Classes DOM (Document Object Model) classes help you to parse or generate XML content.com">' + '<!--Book starts here-->' + '<![CDATA[<Cdata> I like CData </Cdata>]]>' + // Make sure you put the next two lines on one line in your code. The DOM represents an XML document as a hierarchy of nodes.Reference XML Classes w. String result = demo. <sampleElement xmlns:myprefix="http://my.writeCharacters('This is my book'). //end library w. while others are leaf nodes with no children. XML Namespaces An XML namespace is a collection of names identified by a URI reference and used in XML documents to uniquely identify element types and attribute names. '<book xmlns="http://www. System. The DOM classes are contained in the Dom namespace.writeEndDocument().com" author="Manoj">' + 'This is my book</book><ISBN/></m:Library>'.assert(result == expected).name. which contain a single colon. the XML element has two attributes: • The first attribute has a key of dimension. selects a namespace. w. The combination of the universally managed URI namespace and the document's own namespace produces identifiers that are universally unique. Names in XML namespaces may appear as qualified names.space and a prefix of myprefix. which is mapped to a URI reference. 'Manoj'). Use the Document Class to process the content in the body of the XML document. The following XML element has a namespace of http://my.writeEmptyElement(null.getXmlString().0"?><?target data?>' + '<m:Library xmlns:m="http://www. w. You can use these classes to work with any XML content. 'author'. separating the name into a namespace prefix and a local part. String expected = '<?xml version="1. One common application is to use it to create the body of a request for HttpRequest or to parse a response accessed by HttpResponse.writeAttribute(null. Use the XmlNode Class to work with a node in the XML document. 533 . Some nodes may be branch nodes and have child nodes. the value is 2.getXml(). return xmlOutput.close(). The prefix.writeEndElement(). } public static TestMethod void basicTest() { XmlWriterDemo demo = new XmlWriterDemo().space" /> In the following example.book. w. One common application is to use the classes to generate the body of a request created by HttpRequest or to parse a response accessed by HttpResponse. 'ISBN'.defns.writeEndElement(). null). null. String xmlOutput = w. If the prefix argument is null. the namespace is set as the default namespace. see XML Namespaces on page 533. For more information about namespaces. load String xml Void Parse the XML representation of the document specified in the xml argument and load it into a document. the value is bar.XmlNode Returns the top-level root element node in the document. String namespace String prefix The name argument can't have a null value.Reference XML Classes • The second attribute has a key namespace of http://ns1. <square dimension="2" ns1:foo="ns2:bar" xmlns:ns1="http://ns1" xmlns:ns2="http://ns2" /> Methods The Document class has the following methods: Name Arguments Return Type Description createRootElement String name Dom.XmlNode Creates the top-level root element for a document. Salesforce automatically assigns a prefix for the element. Document Example For the purposes of the sample below. assume that the url argument passed into the parseResponseDom method returns this XML response: <address> <name>Kirk Stevens</name> <street1>808 State St</street1> <street2>Apt.load(xml). doc. where i is a number. the root element has not been created yet. 2</street2> <city>Palookaville</city> 534 . The format of the automatic prefix is nsi. the namespace is set as the default namespace.Document(). For example: Dom. getRootElement Dom. toXmlString String Returns the XML representation of the document as a String. the value namespace is http://ns2. Calling this method more than once on a document generates an error as a document can have only one root element. If the prefix argument is ''. the key is foo. If this method returns null. If the namespace argument has a non-null value and the prefix argument is null.Document doc = new Dom. debug(child.XMLNode address = doc. Dom. // print out specific elements System. } } } XmlNode Class Use the XmlNode class to work with a node in an XML document. XmlNodeType is an enum of these different types. Node Types There are different types of DOM nodes available in Apex. // This prints out all the elements of the address for(Dom.debug('Name: ' + name). The following is a simple XML example: <name> <firstName>Suvain</firstName> <lastName>Singh</lastName> </name> 535 . The DOM represents an XML document as a hierarchy of nodes.getRootElement().XMLNode child : address. null).send(req). // Alternatively.Reference XML Classes <state>PA</state> <country>USA</country> </address> The following example illustrates how to use DOM classes to parse the XML response returned in the body of a GET request: public class DomDocument { // Pass in the URL for the request // For the purposes of this sample.Document doc = res.getChildElement('state'.getBodyDocument(). req. System. HttpResponse res = h.getChildElements()) { System.setMethod('GET'). String name = address.getText()). String state = address.setEndpoint(url). HttpRequest req = new HttpRequest().debug('State: ' + state).getText(). //Retrieve the root element for this document. Some nodes may be branch nodes and have child nodes. null).assume that the URL // returns the XML shown above in the response body public void parseResponseDom(String url){ Http h = new Http(). // url that returns the XML in the response body req.getText(). Dom.getChildElement('name'. loop through the child elements. The values are: • • • COMMENT ELEMENT TEXT It is important to distinguish between elements and nodes in an XML document. while others are leaf nodes with no children. Returns the attribute value for the given key and keyNamespace. Creates a child text node for this node. Salesforce automatically assigns a prefix for the element.XmlNode Dom. for the <foo a:b="c:d" /> element: • • getAttribute returns c:d getAttributeValue returns d getAttributeValue String key String String keyNamespace 536 . and lastName element nodes. The name argument can't have a null value. If the prefix argument is null. If the prefix argument is ''. firstName. where i is a number.Reference XML Classes This example contains three XML elements: name. For example. It contains five nodes: the three name. the namespace is set as the default namespace. The format of the automatic prefix is nsi. If the namespace argument has a non-null value and the prefix argument is null. For more information about the methods shared by all enums. Note that the text within an element node is considered to be a separate text node. Index values start at 0. firstName. The text argument can't have a null value.XmlNode String Creates a child comment node for this node.XmlNode Description Creates a child element node for this node. as well as two text nodes—Suvain and Singh. the namespace is set as the default namespace. For more information. Returns the attribute key namespace for the given index. for the <foo a:b="c:d" /> element: • • getAttribute returns c:d getAttributeValue returns d addTextNode getAttribute getAttributeCount getAttributeKeyAt Integer index getAttributeKeyNsAt Integer index Integer String String Returns the number of attributes for this node. see XML Namespaces on page 533. The text argument can't have a null value. Returns namespacePrefix:attributeValue for the given key and keyNamespace. Returns the attribute key for the given index. Methods The XmlNode class has the following methods: Name addChildElement Arguments String name String namespace String prefix Return Type Dom. addCommentNode String text String text String key String keyNamespace Dom. For example. see Enum Methods on page 339. and lastName. Dom. Returns true if successful.XmlNode[] Returns the child nodes for this node. getAttributeValueNs String key String keyNamespace getChildElement String name String namespace Dom. This doesn't include child text or comment nodes.XmlNode String namespace String Returns the parent of this element. Returns the text for this node.XmlNode[] Returns the child element nodes for this node. Returns the namespace of the element for the given prefix. For more information. getText removeAttribute String String key String keyNamespace Boolean removeChild Dom. see XML Namespaces. setNamespace String prefix String namespace Void Sets the namespace for the given prefix. String String String prefix String Returns the element name. see XML Namespaces. Dom. For more information.Reference XML Classes Name Arguments Return Type String Description Returns the attribute value namespace for the given key and keyNamespace. For more information. For more information. For more information. see XML Namespaces. see Node Types. The namespace argument can't have a null value. see Node Types.XmlNode childNode Boolean Void setAttribute String key String value setAttributeNs String key String value String keyNamespace String valueNamespace Void Sets the key attribute value. see XML Namespaces. Removes the attribute with the given key and keyNamespace. For more information. false otherwise.XmlNodeType Returns the node type. Returns the namespace of the element. see XML Namespaces. Returns the prefix of the given namespace. see XML Namespaces. Sets the key attribute value. Returns the child element node for the node with the given name and namespace.XmlNode getChildElements Dom. see XML Namespaces. Removes the given childNode. getChildren getName getNamespace getNamespaceFor getNodeType getParent getPrefixFor Dom. For more information. For more information. For more information. This includes all node types. 537 . String xsi = 'http://www.setHeader('Content-Type'.w3. wsa). System. System. String wsa = 'http://schemas. soapNS).xmlsoap. System. wsa). String soapNS = 'http://schemas.getText()). null). System.getChildElement('Address'. null).addChildElement('echo'. xsi.getStatusCode()). 538 . header.toXmlString()).getChildElement('Header'. Http http = new Http().setNamespace('xsi'.Document resDoc = res.assert(header != null). envelope. dom. soapNS. req. dom. System.xmlsoap.assertEquals( 'http://schemas. null).Document doc = new DOM.debug(resDoc).XmlNode body = envelope.getChildElement( 'ReplyTo'. dom. serviceNS. String messageId = header.assertEquals(200. req.getRootElement().debug(header).myservice.org/2001/XMLSchema-instance'. 'soapenv').xmlsoap.Document().setMethod('POST'). soapNS.org/ws/2004/08/addressing/role/anonymous'.getText().org/soap/envelope/'. System. String serviceNS = 'http://www. 'text/xml').Reference XML Classes XmlNode Example This example shows how to use XmlNode methods and namespaces to create an XML request.send(req). System. For a basic example using XmlNode methods.setAttributeNS('schemaLocation'.setEndpoint(endpoint). res. public class DomNamespaceSample { public void sendRequest(String endpoint) { // Create the request envelope DOM. req. dom.toXmlString()). addTextNode('classifieds').org/ws/2004/08/addressing'.debug(resDoc. wsa).addChildElement('Body'. req.setBodyDocument(doc). envelope = resDoc.getBodyDocument(). // Send the request HttpRequest req = new HttpRequest(). HttpResponse res = http.com/services/MyService/'. System. serviceNS.getChildElement('MessageID'. 'req').XmlNode header = envelope. xsi).debug(messageId). see Document Class on page 533.XmlNode envelope = doc. envelope.createRootElement('Envelope'. soapNS.debug(doc. addChildElement('category'. body. serviceNS). envelope.else'). see the following: ◊ ◊ ◊ ◊ • ProcessRequest Class on page 540 ProcessResult Class on page 541 ProcessSubmitRequest Class on page 541 ProcessWorkitemRequest Class on page 542 The Approval namespace process method: Use this to submit an approval request. getChildElement('echo'. serviceNS). See Understanding Execution Governors and Limits on page 214. getChildElement('echo'. as well as approve or reject existing approval requests. 'http://something. // Create an approval request for the account Approval. } } Apex Approval Processing Classes An approval process is an automated process your organization can use to approve records in Salesforce. Apex provides support for creating a programmatic approval process to extend your existing approval processes with the following: • The Apex process classes: Use these to create approval requests. getChildElement('something'.assertEquals( envelope. For more information.getChildElement('Body'. System. or just records that have certain attributes. serviceNS). serviceNS). getChildElement('category'. then approves the request.assertEquals('classifieds'. soapNS). For more information on approval processes. see “Getting Started with Approval Processes” in the Salesforce online help.getText()). getChildElement( 'whatever'. rejected. see Approval Methods on page 374. insert a. An approval process specifies the steps necessary for a record to be approved and who must approve it at each step. public class TestApproval { void submitAndProcessApprovalRequest() { // Insert an account Account a = new Account(Name='Test'. An approval process also specifies the actions to take when a record is approved. or first submitted for approval.getAttribute('bb'.0). null). Note: The process method counts against the DML limits for your organization. soapNS).Reference Apex Approval Processing Classes System. For more information.getChildElement('Body'. This example requires an approval process to be set up for accounts. 'cc').annualRevenue=100. Apex Approval Processing Example The following sample code initially submits a record for approval. A step can apply to all records included in the process. as well as process the results of those requests. recalled.ProcessSubmitRequest req1 = 539 . // Approve the submitted request // First. The ProcessRequest class has the following methods. Returns the list of user IDs of user specified as approvers.assert(result2.ProcessResult result2 = Approval. The constructor for this class takes no arguments. req2. result2. Name getComments Arguments Return Type String ID[] Description Returns the comments that have been added previously to the approval request.setWorkitemId(newWorkItemIds.setComments('Approving request.getInstanceStatus().ProcessWorkitemRequest(). // Verify the result System.setObjectId(a. result.getUserId()}).isSuccess()). // Instantiate the new ProcessWorkitemRequest object and populate it Approval. For example: Approval.ProcessRequest pr = new Approval. getNextApproverIds 540 . // Submit the approval request for the account Approval. 'Result Status:'+result2.get(0)). } } ProcessRequest Class The ProcessRequest class is the parent class for the ProcessSubmitRequest and ProcessWorkitemResult classes.getNewWorkitemIds(). // Verify the results System.isSuccess()).id). Use the ProcessRequest class to write generic Apex that can process objects from either class.ProcessRequest().setAction('Approve').ProcessSubmitRequest(). req1.isSuccess().assertEquals( 'Approved'. req1.'). 'Instance Status'+result.process(req1).ProcessWorkitemRequest req2 = new Approval. get the ID of the newly created item List<Id> newWorkItemIds = result.getInstanceStatus().setComments('Submitting request for approval.getInstanceStatus()).assertEquals( 'Pending'.process(req2). // Use the ID from the newly created item to specify the item to be worked req2. req2. System.setNextApproverIds(new Id[] {UserInfo. System. req2. // Submit the request for approval Approval.Reference Apex Approval Processing Classes new Approval.'). 'Instance Status'+result2.ProcessResult result = Approval. You must specify the Approval namespace when creating an instance of this class.getInstanceStatus()).assert(result. 541 . These methods take no arguments. Rejected. see Database Error Object Methods on page 389.ProcessResult result = Approval. getInstanceId String String ID[] Boolean getInstanceStatus getNewWorkitemIds isSuccess ProcessSubmitRequest Class Use the ProcessSubmitRequest class to submit a record for approval.process(req1). If not. Name getEntityId getErrors Return Type String Database.ProcessSubmitRequest psr = new Approval. A ProcessResult object is returned by the process method. setNextApproverIds ProcessResult Class After you submit a record for approval. A Boolean value that is set to true if the approval process completed successfully.ProcessSubmitRequest(). The IDs of the new items submitted to the approval process. For more information. it is set to false. The status of the current approval process. You must specify the Approval namespace when creating an instance of this class. use the ProcessResult class to process the results of an approval process. The ProcessResult class has the following methods. otherwise.Error[] Description The ID of the record being processed. For example: Approval. If the next step in your approval process is another Apex approval process. Valid values are: Approved.Reference Apex Approval Processing Classes Name setComments Arguments String ID[] Return Type Void Void Description The comments to be added to the approval request. For example: Approval. you specify exactly one user ID as the next approver. The constructor for this class takes no arguments. If an error occurred. You must specify the Approval namespace when creating an instance of this class. There can be 0 or 1 approval processes. returns an array of one or more database error objects including the error code and description. Removed or Pending. you cannot specify a user ID and this method must be null. The ID of the approval process that has been submitted for approval. For example. In addition to these methods. it can specify an account. In addition to these methods. The following methods are unique to the ProcessWorkitemRequest class. or Removed. you specify exactly one user ID as the next approver. ProcessRequest.ProcessWorkitemRequest(). getNextApproverIds setComments String ID[] Void Void setNextApproverIds ProcessWorkitemRequest Class Use the ProcessWorkitemRequest class for processing an approval request after it is submitted. Valid values are: Approve. contact. Name getComments Arguments Return Type String ID[] Description Returns the comments that have been added previously to the approval request. the ProcessSubmitRequest class has access to all the methods in its parent class. or custom object record. Returns the list of user IDs of user specified as approvers. For example. Reject. Name getObjectId Arguments Return Type String Description Returns the ID of the record that has been submitted for approval. The comments to be added to the approval request. For example: Approval. the ProcessWorkitemRequest class has access to all the methods in its parent class. If the next step in your approval process is another Apex approval process. contact.ProcessWorkitemRequest pwr = new Approval. or custom object record. 542 . You must specify the Approval namespace when creating an instance of this class. it can return an account.Reference Apex Approval Processing Classes The following methods are unique to the ProcessSubmitRequest class. setObjectId String Id Void The ProcessSubmitRequest class shares the following methods with ProcessRequest. Name getAction Arguments Return Type String Description Returns the type of action already associated with the approval request. If not. Sets the ID of the record to be submitted for approval. The constructor for this class takes no arguments. ProcessRequest. you cannot specify a user ID and this method must be null. rejected. Valid values are: Approve. or removed. Apex includes the following support classes: • • BusinessHours Class Cases Class BusinessHours Class Business hours are used to specify the hours at which your customer support team operates. The comments to be added to the approval request. The following are the instance methods for BusinessHours. Sets the type of action to take for processing an approval request. If the next step in your approval process is another Apex approval process. If not. Name getComments Arguments Return Type String ID[] Description Returns the comments that have been added previously to the approval request. Sets the ID of the approval request that is being approved. Only system administrators can specify Removed. setAction String s Void setWorkitemId String Id Void The ProcessWorkitemRequest class shares the following methods with ProcessRequest. getNextApproverIds setComments String ID[] Void Void setNextApproverIds Apex Support Classes Support classes allow you to interact with records commonly used by support centers. 543 . you cannot specify a user ID and this method must be null. or Removed. such as business hours and cases. Reject. BusinessHours methods are all called by and operate on a particular instance of a business hour. Returns the list of user IDs of user specified as approvers.Reference Apex Support Classes Name getWorkitemId Arguments Return Type String Description Returns the ID of the approval request that is in the process of being approved. rejected. or removed. you specify exactly one user ID as the next approver. including multiple business hours in multiple time zones. 1. Datetime startDate Long interval addGmt String businessHoursId Datetime Datetime startDate Adds an interval of milliseconds from a start Datetime traversing business hours only. For an example. returning the Datetime in GMT: // Get the default business hours BusinessHours bh = [SELECT Id FROM BusinessHours WHERE IsDefault=true]. 2008 at 1:06:08 AM in local timezone. Datetime startTime = Datetime. 2008. see “Setting Business Hours” in the Salesforce online help. Datetime endDate For more information on business hours. 1.Reference Apex Support Classes Name add Arguments String businessHoursId Return Type Datetime Description Adds an interval of milliseconds from a start Datetime traversing business hours only. 8). Datetime nextTimeGmt = BusinessHours. 2008 at 1:06:08 AM in local timezone. 5. Long interval diff String businessHoursId Long Datetime startDate Returns the difference between a start and end Datetime based on a specific set of business hours. 28. 1:06:08 AM using the // default business hours.addGmt(bh. 1:06:08 AM using the // default business hours. Datetime nextTime = BusinessHours. 8). The next example finds the difference between startTime and nextTime: // Get the default business hours BusinessHours bh = [select id from businesshours where IsDefault=true]. Datetime startTime = Datetime. For an example. Returns the result Datetime in the local time zone. 6.add(bh. BusinessHours Examples The following example finds the time one business hour from startTime. 5. startTime. 2008. The returned Datetime will be in the local timezone. 544 . 28. The returned Datetime will be in GMT. 60 * 60 * 1000L). // Create Datetime on May 28. 60 * 60 * 1000L). // Create Datetime on May 28. This example finds the time one business hour from startTime.newInstance(2008. // Find the time it will be one business hour from May 28. startTime. 6. For an example.id. returning the Datetime in the local time zone: // Get the default business hours BusinessHours bh = [SELECT Id FROM BusinessHours WHERE IsDefault=true]. Returns the result Datetime in GMT. see BusinessHours Examples on page 544.newInstance(2008.id. // Find the time it will be one business hour from May 28. see BusinessHours Examples on page 544. see BusinessHours Examples on page 544. 16. // Call Apex method to retrieve case ID from email thread ID ID caseId = Cases.diff(bh._500xxYktl:ref]. positive value otherwise. } } Apex Community Classes Communities help organize ideas and answers into logical groups with each community having its own focus and unique ideas and answers topics. 5._500xxYktg'. endTime). 2008 at 4:06:08 PM in local timezone. Other formats. 5. startTime. Apex includes the following classes related to a community: 545 . // Find the number of business hours milliseconds between startTime and endTime as // defined by the default business hours. Method Arguments Return Type Description Returns the case ID corresponding to the specified email thread ID. Long diff = BusinessHours. 8). 8).newInstance(2008. Datetime endTime = Datetime. 6. 28._500xxYktl:ref and [ref:_00Dxx1gEW. Cases Example The following example uses an email thread ID to retrieve the related case ID. such as ref:_00Dxx1gEW.id.newInstance(2008.Reference Apex Community Classes // Create Datetime on May 28._500xxYktg. Methods The following is the static method of the Cases class. getCaseIdFromEmailThreadId String emailThreadId ID are invalid. Datetime startTime = Datetime. Will return a negative value if endTime is // before startTime. // Create Datetime on May 28. 0 if equal.getCaseIdFromEmailThreadId(emailThreadId). public class GetCaseIdController { public static void getCaseIdSample() { // Get email thread ID String emailThreadId = '_00Dxx1gEW. 28. 1. Cases Class Usage Use the Cases class to interact with case records. 2008 at 1:06:08 AM in local timezone. The emailThreadId argument should have the following format: _00Dxx1gEW. 6. question. ID[] results = Answers. Each findSimilar call counts against the SOSL statements governor limit allowed for the process. Answers Example The following example finds questions in a specific community (INTERNAL_COMMUNITY) that have similar titles as a new question: public class FindSimilarQuestionController { public static void test() { // Instantiate a new question Question question = new Question ().Reference Apex Community Classes • • Answers Class Ideas Class See Also: Answers Class Ideas Class Answers Class Answers is a feature of the Community application that enables users to ask questions and have community members post replies. Community members can then vote on the helpfulness of each reply. Sets the specified reply for the specified question as the best reply.id. Community community = [ SELECT Id FROM Community WHERE Name = 'INTERNAL_COMMUNITY' ]. Question question ID[] setBestReply String questionId Void String replyId For more information on answers.title = 'How much vacation time do full-time employees get?'. Because a question can have multiple replies. Name findSimilar Arguments Return Type Description Returns a list of similar questions based on the title of question. The following are the static methods for answers. see “Answers Overview” in the Salesforce online help. // Specify a title for the new question question.findSimilar(question). and the person who asked the question can mark one reply as the best answer. setting the best reply helps users quickly identify the reply that contains the most helpful information. } } 546 . // Specify the communityID (INTERNAL_COMMUNITY) in which to find similar questions.communityId = community. Id. Name findSimilar Arguments Idea idea Return Type ID[] Description Returns a list similar ideas based on the title of idea. and comment on ideas. Answers. If this argument is the empty string. ID replyID = [SELECT Id FROM Reply WHERE QuestionId = :questionId LIMIT 1]. Consider it an online suggestion box that includes discussions and popularity rankings for any subject. vote for. 547 . see below) includes ideas that a user has posted or commented on that already have comments posted by another user. then all recent replies for the specified user are returned regardless of the community. A set of recent replies (returned by methods.Reference Apex Community Classes The following example marks a reply as the best reply: ID questionId = [SELECT Id FROM Question WHERE Title = 'Testing setBestReplyId' LIMIT 1]. Returns ideas that have recent replies for the specified user or community. Returns ideas that have recent replies marked as read.replyId). The communityID argument filters the results so only the ideas within the specified community are returned. The userID argument is a required argument that filters the results so only the ideas that the specified user has posted or commented on are returned.setBestReply(questionId. The returned ideas are listed based on the time of the last comment made by another user. The following are the static methods for ideas. See Also: Apex Community Classes Ideas Class Ideas Class Ideas is a community of users who post. This includes all read and unread replies.Id. with the most recent ideas appearing first. Each findSimilar call counts against the SOSL statement governor limit allowed for the process. getAllRecentReplies String userID String communityID ID[] getReadRecentReplies String userID String communityID ID[] getUnreadRecentReplies String userID ID[] String communityID Returns ideas that have recent replies marked as unread. markRead String ideaID Void Marks all comments as read for the user that is currently logged in. there must be ideas posted to the community. idea. In addition. <apex:page controller="IdeasController" showHeader="false"> <apex:dataList value="{!unreadRecentReplies}" var="recentReplyIdea"> <a href="/apex/viewIdea?id={!recentReplyIdea. // Create an Apex method to retrieve the recent replies marked as unread in all communities public class IdeasController { public Idea[] getUnreadRecentReplies() { Idea[] recentReplies.Title = 'Increase Vacation Time for Employees'. } } The following is the markup for a Visualforce page that uses the above custom controller to list unread recent replies. a special Apex class.findSimilar(idea). see the Visualforce Developer's Guide. that is. For more information on Visualforce. Ideas Examples The following example finds ideas in a specific community that have similar titles as a new idea: public class FindSimilarIdeasController { public static void test() { // Instantiate a new idea Idea idea = new Idea (). // Specify a title for the new idea idea.getUnreadRecentReplies(UserInfo. ''). For this example to work. Community community = [ SELECT Id FROM Community WHERE Name = 'INTERNAL_IDEAS' ]. // Specify the communityID (INTERNAL_IDEAS) in which to find similar ideas.Reference Apex Community Classes For more information on ideas. } return recentReplies.CommunityId = community. This example creates an Apex method in the controller that returns unread recent replies. You can leverage this same example for the getAllRecentReplies and getReadRecentReplies methods.Id}"> <apex:outputText value="{!recentReplyIdea. at least one community member must have posted a comment to another community member's idea or comment. Title FROM Idea WHERE Id IN :recentRepliesIds].getUserId(). if (recentReplies == null) { Id[] recentRepliesIds = Ideas.Id. } } The following example uses a Visualforce page in conjunction with a custom controller. see “Using Ideas” in the Salesforce online help. ID[] results = Ideas.Title}" escape="true"/></a> </apex:dataList> </apex:page> 548 . recentReplies = [SELECT Id. there must be ideas posted to the community.id}"> <apex:outputText value="{!idea. <apex:page standardController="Idea" extensions="ViewIdeaController" showHeader="false"> <h2><apex:outputText value="{!idea. at least one community member must have posted a comment to another community member's idea or comment. to display the idea that is selected on the above idea list page.} public IdeaListController() { Integer i = 0. } } The following is the markup for a Visualforce page that uses the above custom controller to display the idea as read.currentPage().markRead(id).Reference Apex Community Classes The following example uses a Visualforce page in conjunction with a custom controller to list ideas. // Create an Apex method in the controller that marks all comments as read for the // selected idea public class ViewIdeaController { private final String id = System. this time. For this example to work.query ('SELECT Id.StandardController controller) { Ideas.add(tmp). there must be ideas posted to the community. for (Idea tmp : Database.title}" escape="true"/></a> </apex:dataList> </apex:page> The following example also uses a Visualforce page and custom controller. For this example to work. Note that the markRead method is in the constructor so that the idea is marked read immediately when the user goes to a page that uses this controller.body}" /> 549 . } } } The following is the markup for a Visualforce page that uses the above custom controller to list ideas: <apex:page controller="IdeaListController" tabStyle="Idea" showHeader="false"> <apex:dataList value="{!ideas}" var="idea" id="ideaList"> <a href="/apex/viewIdea?id={!idea. // Create a controller to use on a VisualForce page to list ideas public class IdeaListController { public final Idea[] ideas {get.get('id'). ideas. In this example. a second Visualforce page and custom controller is used to display a specific idea and mark it as read. ideas = new Idea[10]. private set. In addition. Then. public ViewIdeaController(ApexPages. Title FROM Idea WHERE Id != null AND parentIdeaId = null LIMIT 10')) { i++.title}" /></h2> <apex:outputText value="{!idea. the markRead method marks the selected idea and associated comments as read by the user that is currently logged in.getParameters(). Datetime scheduledDate = Datetime. String articleId = 'Insert article ID'.Reference Knowledge Management Publishing Service Class </apex:page> See Also: Apex Community Classes Answers Class IdeaStandardController Class IdeaStandardSetController Class Knowledge Management Publishing Service Class Usage Use the methods in the KbManagement. scheduledDate).0).1. it archives the article on the scheduled date.PublishingService class to manage the following parts of the lifecycle of an article and its translations: • • • • • • • • Publishing Updating Retrieving Deleting Submitting for translation Setting a translation to complete or incomplete status Archiving Assigning review tasks for draft articles or translations Note: Date values are based on GMT.PublishingService.30. To use the methods in this class. the article is archived immediately.newInstanceGmt(2012. KbManagement. Otherwise. 550 .13. Method archiveOnlineArticle Arguments String articleId Datetime scheduledDate Return Type Void Description Archives an online version of an article. See Salesforce Knowledge Implementation Guide for more information on setting up Salesforce Knowledge. If scheduledDate is null. 12. you must enable Salesforce Knowledge. archiveOnlineArticle (articleId. Methods The following are static methods of the KbManagement.PublishingService class. String articleId = 'Insert article ID'. Datetime dueDate = Datetime. String assigneeId = 'Insert assignee ID'. cancelScheduledArchivingOfArticle (articleId). cancelScheduledPublicationOfArticle (articleId).Reference Knowledge Management Publishing Service Class Method assignDraftArticleTask Arguments String articleId String assigneeID String instructions Return Type Void Description Assigns a review task related to a draft article. String articleId = 'Insert article ID'. dueDate. Datetime dueDate Boolean sendEmailNotification assignDraftTranslationTask String Void articleVersionId Assigns a review task related to a draft translation. KbManagement. assignDraftTranslationTask (articleId.PublishingService. 12. String articleId = 'Insert article ID'.PublishingService. 551 . instructions.PublishingService. String instructions = 'Please review this draft. true).1). KbManagement. assigneeId. String articleId = 'Insert article ID'. assignDraftArticleTask (articleId. Datetime dueDate = Datetime. completeTranslation(articleVersionId). String instructions = 'Please review this draft.'. KbManagement. instructions. dueDate.'. cancelScheduledPublication String articleId OfArticle Void Cancels the scheduled publication of a draft article. String assigneeID String instructions DatetimedueDate Boolean sendEmailNotification cancelScheduledArchiving OfArticle String articleId Void Cancels the scheduled archiving of an online article.newInstanceGmt(2012. KbManagement. true). 12. KbManagement. String assigneeId = 'Insert assignee ID'.PublishingService.1).newInstanceGmt(2012.PublishingService. completeTranslation String articleVersionId Void Puts a translation in a completed state that is ready to publish. String articleVersionId = 'Insert article version ID'. assigneeId. deleteDraftTranslation (articleVersionId). editOnlineArticle (articleId.PublishingService. String id = KbManagement. String articleId = 'Insert article ID'. String articleId = 'Insert article ID'. KbManagement. if unpublish is set to true. Integer versionNumber deleteDraftArticle String articleId Void Deletes a draft article. String articleVersionId = 'Insert article version ID'. String id = KbManagement.PublishingService. deleteArchivedArticleVersion String articleId Void Deletes a specific version of an archived article. Integer versionNumber = 1.Reference Knowledge Management Publishing Service Class Method deleteArchivedArticle Arguments String articleId Return Type Void Description Deletes an archived article.PublishingService. KbManagement. deleteArchivedArticle(articleId). KbManagement. KbManagement. deleteDraftTranslation String articleVersionId Void Deletes a draft translation. editArchivedArticle String articleId String Creates a draft article from the archived master version and returns the new draft master version ID of the article. editArchivedArticle(articleId). String articleId = 'Insert article ID'.PublishingService.PublishingService. String articleId = 'Insert article ID'. unpublishes the online article.PublishingService. editOnlineArticle String articleId Boolean unpublish String Creates a draft article from the online version and returns the new draft master version ID of the article. deleteArchivedArticleVersion (articleId. String articleId = 'Insert article ID'. true). versionNumber). deleteDraftArticle(articleId). Also. 552 . language. String id = KbManagement. scheduledDate). String articleVersionId = 'Insert article version ID'. setTranslationToIncomplete String Void articleVersionId Sets a draft translation that is ready for publication back to “in progress” status. String articleId = 'Insert article ID'. String language = 'fr'. String id = KbManagement. Datetime scheduledDate = Datetime. publishArticle String articleId Boolean flagAsNew Void Publishes an article. KbManagement. scheduleForPublication(articleId. setTranslationToIncomplete(articleVersionId). Also.PublishingService.13. publishArticle(articleId. if set to true. KbManagement. restoreOldVersion String articleId Integer versionNumber String Creates a draft article from an existing online article based on the specified archived version of the article and returns the article version ID.Reference Knowledge Management Publishing Service Class Method editPublishedTranslation Arguments String articleId String language Boolean unpublish Return Type String Description Creates a draft version of the online translation for a specific language and returns the new draft master version ID of the article. KbManagement.PublishingService. the article is published as a major version. true).PublishingService.newInstanceGmt(2012. String articleId = 'Insert article ID'. String articleId = 'Insert article ID'. 12. scheduleForPublication String articleId Datetime scheduledDate Void Schedules the article for publication as a major version. unpublishes the article.PublishingService.PublishingService. 1). editPublishedTranslation(articleId. String articleId = 'Insert article ID'.0). true). If scheduledDate is null.1. 553 . restoreOldVersion (articleId. the article is published immediately.30. If flagAsNew is set to true. Reference Site Class Method submitForTranslation Arguments String articleId String language String assigneeID Datetime dueDate Return Type String Description Submits an article for translation to the specified language. Also assigns the specified user and due date to the submittal and returns new ID of the draft translation. String articleId = 'Insert article ID'; String language = 'fr'; String assigneeId = 'Insert assignee ID'; Datetime dueDate = Datetime.newInstanceGmt(2012, 12,1); String id = KbManagement.PublishingService. submitForTranslation(articleId, language, assigneeId, dueDate); Site Class The following are the static methods for the Site class, which is part of Force.com sites. Name changePassword Arguments String newpassword String verifynewpassword Return Type System.PageReference Description Changes the password of the current user. String opt_oldpassword createPersonAccount PortalUser sObject user String ownerId String password ID Creates a person account using the default record type defined on the guest user's profile, then enables it for the site's portal. Note: This method is only valid when a site is associated with a Customer Portal, and when the user license for the default new user profile is a high-volume portal user. 554 Reference Site Class Name createPersonAccount PortalUser Arguments sObject user String ownerId String recordTypeId String password Return Type ID Description Creates a person account using the specified recordTypeID, then enables it for the site's portal. Note: This method is only valid when a site is associated with a Customer Portal, and when the user license for the default new user profile is a high-volume portal user. createPortalUser sObject user String accountId String opt_password Boolean opt_sendEmailConfirmation ID Creates a portal user for the given account and associates it with the site's portal. The optional opt_password argument is the password of the portal user. If not specified, or if set to null or an empty string, this method sends a new password email to the portal user. The optional opt_sendEmailConfirmation argument determines whether a new user email is sent to the portal user. Set it to true to send a new user email to the portal user. The default is false, that is, the new user email isn't sent. The nickname field is required for the user sObject when using the createPortalUser method. Note: This method is only valid when a site is associated with a Customer Portal. forgotPassword String username Boolean Resets the user's password and sends an email to the user with their new password. Returns a value indicating whether the password reset was successful or not. 555 Reference Site Class Name getAdminEmail Arguments Return Type String ID String Description Returns the email address of the site administrator. Returns the user ID of the site administrator. The tracking code associated with your site. This code can be used by services like Google Analytics to track page request data for your site. Returns the value of the site URL for the current request (for example, http://myco.com/ or https://myco.force.com/prefix/). Returns the value of the Custom Web Address field for the current site. Returns the Force.com domain name for your organization. Returns the error description for the current page if it’s a designated error page for the site and an error exists; otherwise, returns an empty string. Returns an error message for the current page if it’s a designated error page for the site and an error exists; otherwise, returns an empty string. Returns the API name of the current site. Returns the original URL for this page if it’s a designated error page for the site; otherwise, returns null. Returns the URL path prefix of the current site. For example, if your site URL is myco.force.com/partners, partners is the path prefix. Returns null if the prefix is not defined, or if the page was accessed using a custom Web address. getAdminId getAnalyticsTrackingCode getCurrentSiteUrl String getCustomWebAddress String getDomain String String getErrorDescription getErrorMessage String getName String String getOriginalUrl getPrefix String 556 Reference Site Class Name getTemplate Arguments Return Type System.PageReference Description Returns the template name associated with the current site; returns the default template if no template has been designated. Returns true if the current site is associated with an active login-enabled portal; otherwise returns false. For authenticated users, returns true if the currently logged-in user's password is expired. For non-authenticated users, returns false. Returns true if the current site is associated with an active self-registration-enabled Customer Portal; otherwise returns false. Allows users to log in to the current site with the given username and password, then takes them to the startUrl If startUrl is not a relative path, it defaults to the site's designated index page. Note: Do not include http:// or https:// in the startURL. isLoginEnabled Boolean isPasswordExpired Boolean isRegistrationEnabled Boolean login String username String password String startUrl System.PageReference setPortalUserAsAuthProvider sObject user Void String contactId Sets the specified user information within the site’s portal via an authentication provider. • This method is only valid when a site is associated with a Customer Portal. For more information on an authentication provider, see Auth.RegistrationHandler. • For more information on sites, see “Force.com Sites Overview” in the Salesforce online help. 557 Reference Site Class Force.com Sites Examples The following example creates a class, SiteRegisterController, which is used with a Visualforce page (see markup below) to register new Customer Portal users. Note: In the example below, you must enter the account ID of the account that you want to associate with new portal users. You must also add the account owner to the role hierarchy for this code example to work. For more information, see “Setting Up Your Customer Portal” in the Salesforce online help. /** * An Apex class that creates a portal user */ public class SiteRegisterController { // PORTAL_ACCOUNT_ID is the account on which the contact will be created on // and then enabled as a portal user. //Enter the account ID in place of <portal_account_id> below. private static Id PORTAL_ACCOUNT_ID = '<portal_account_id>'; public SiteRegisterController () { } public String username {get; set;} public String email {get; set;} public String password {get; set {password = value == null ? value : value.trim(); } } public String confirmPassword {get; set { confirmPassword = value == null ? value : value.trim(); } } public String communityNickname {get; set { communityNickname = \ value == null ? value : value.trim(); } } private boolean isValidPassword() { return password == confirmPassword; } public PageReference registerUser() { // If password is null, a random password is sent to the user if (!isValidPassword()) { ApexPages.Message msg = new ApexPages.Message(ApexPages.Severity.ERROR, Label.site.passwords_dont_match); ApexPages.addMessage(msg); return null; } User u = new User(); u.Username = username; u.Email = email; u.CommunityNickname = communityNickname; String accountId = PORTAL_ACCOUNT_ID; // lastName is a required field on user, but if it isn't specified, the code uses the username String userId = Site.createPortalUser(u, accountId, password); if (userId != null) { if (password != null && password.length() > 1) { return Site.login(username, password, null); } else { PageReference page = System.Page.SiteRegisterConfirm; page.setRedirect(true); return page; } } return null; } // Test method for verifying the positive test case static testMethod void testRegistration() { 558 Reference Cookie Class SiteRegisterController controller = new SiteRegisterController(); controller.username = '
[email protected]'; controller.email = '
[email protected]'; controller.communityNickname = 'test'; // registerUser always returns null when the page isn't accessed as a guest user System.assert(controller.registerUser() == null); controller.password = 'abcd1234'; controller.confirmPassword = 'abcd123'; System.assert(controller.registerUser() == null); } } The following is the Visualforce registration page that uses the SiteRegisterController Apex controller above: <apex:page id="Registration" showHeader="false" controller= "SiteRegisterController" standardStylesheets="true"> <apex:outputText value="Registration"/> <br/> <apex:form id="theForm"> <apex:messages id="msg" styleClass="errorMsg" layout="table" style="margin-top:1em;"/> <apex:panelGrid columns="2" style="margin-top:1em;"> <apex:outputLabel value="{!$Label.site.username}" for="username"/> <apex:inputText required="true" id="username" value="{!username}"/> <apex:outputLabel value="{!$Label.site.community_nickname}" for="communityNickname"/> <apex:inputText required="true" id="communityNickname" required="true" value="{!communityNickname}"/> <apex:outputLabel value="{!$Label.site.email}" for="email"/> <apex:inputText required="true" id="email" required="true" value="{!email}"/> <apex:outputLabel value="{!$Label.site.password}" for="password"/> <apex:inputSecret id="password" value="{!password}"/> <apex:outputLabel value="{!$Label.site.confirm_password}" for="confirmPassword"/> <apex:inputSecret id="confirmPassword" value="{!confirmPassword}"/> <apex:outputText value=""/> <apex:commandButton action="{!registerUser}" value="{!$Label.site.submit}" id="submit"/> </apex:panelGrid> </apex:form> cod</apex:page> The sample code for the createPersonAccountPortalUser method is nearly identical to the sample code above, with the following changes: • • Replace all instances of PORTAL_ACCOUNT_ID with OWNER_ID. Determine the ownerID instead of the accountID, and use the createPersonAccountPortalUser method instead of the CreatePortalUser method by replacing the following code block: String accountId = PORTAL_ACCOUNT_ID; String userId = Site.createPortalUser(u, accountId, password); with String ownerId = OWNER_ID; String userId = Site.createPersonAccountPortalUser(u, ownerId, password); Cookie Class The Cookie class lets you access cookies for your Force.com site using Apex. 559 Reference Cookie Class Use the setCookies method of the pageReference class to attach cookies to a page. Important: • • • • • Cookie names and values set in Apex are URL encoded, that is, characters such as @ are replaced with a percent sign and their hexadecimal representation. The setCookies method adds the prefix “apex__” to the cookie names. Setting a cookie's value to null sends a cookie with an empty string value instead of setting an expired attribute. After you create a cookie, the properties of the cookie can't be changed. Be careful when storing sensitive information in cookies. Pages are cached regardless of a cookie value. If you use a cookie value to generate dynamic content, you should disable page caching. For more information, see “Caching Force.com Sites Pages” in the Salesforce online help. Consider the following limitations when using the Cookie class: • • • The Cookie class can only be accessed using Apex that is saved using the Salesforce.com API version 19 and above. The maximum number of cookies that can be set per Force.com domain depends on your browser. Newer browsers have higher limits than older ones. Cookies must be less than 4K, including name and attributes. The following are the instance methods for the Cookie class, which is part of Force.com sites. Name getDomain Arguments Return Type String Integer Description Returns the name of the server making the request. Returns a number representing how long the cookie is valid for, in seconds. If set to < 0, a session cookie is issued. If set to 0, the cookie is deleted. Returns the name of the cookie. Can't be null. Returns the path from which you can retrieve the cookie. If null or blank, the location is set to root, or “/”. Returns the data captured in the cookie, such as Session ID. Returns true if the cookie can only be accessed through HTTPS, otherwise returns false. getMaxAge getName String String getPath getValue String Boolean isSecure For more information on sites, see “Force.com Sites Overview” in the Salesforce online help. 560 Reference Network Class The following example creates a class, CookieController, which is used with a Visualforce page (see markup below) to update a counter each time a user displays a page. The number of times a user goes to the page is stored in a cookie. // A Visualforce controller class that creates a cookie // used to keep track of how often a user displays a page public class CookieController { public CookieController() { Cookie counter = ApexPages.currentPage().getCookies().get('counter'); // If this is the first time the user is accessing the page, // create a new cookie with name 'counter', an initial value of '1', // path 'null', maxAge '-1', and isSecure 'false'. if (counter == null) { counter = new Cookie('counter','1',null,-1,false); } else { // If this isn't the first time the user is accessing the page // create a new cookie, incrementing the value of the original count by 1 Integer count = Integer.valueOf(counter.getValue()); counter = new Cookie('counter', String.valueOf(count+1),null,-1,false); } // Set the new cookie for the page ApexPages.currentPage().setCookies(new Cookie[]{counter}); } // This method is used by the Visualforce action {!count} to display the current // value of the number of times a user had displayed a page. // This value is stored in the cookie. public String getCount() { Cookie counter = ApexPages.currentPage().getCookies().get('counter'); if(counter == null) { return '0'; } return counter.getValue(); } // Test method for verifying the positive test case static testMethod void testCounter() { //first page view CookieController controller = new CookieController(); System.assert(controller.getCount() == '1'); //second page view controller = new CookieController(); System.assert(controller.getCount() == '2'); } } The following is the Visualforce page that uses the CookieController Apex controller above. The action {!count} calls the getCount method in the controller above. <apex:page controller="CookieController"> You have seen this page {!count} times </apex:page> Network Class Represents a community. 561 Reference Connect in Apex—Developer Preview Usage Use the method in the Network class to determine which community a user is currently logged into. Note: Salesforce Communities is available through a pilot program. Contact your Salesforce.com representative to find out if your organization qualifies for the pilot. Methods The Network class contains the following static method. This method takes no arguments. Method getNetworkId Return Type String Description Returns the user’s current community. If Communities isn’t enabled for the user’s organization or the user is currently in the internal organization, returns null. Connect in Apex—Developer Preview Note: Connect in Apex is currently available as a Developer Preview in all Developer Editions. For information on enabling Connect in Apex in other editions, contact salesforce.com. Connect in Apex exposes Chatter API data as Apex objects. Use classes in the ConnectApi namespace to develop Chatter applications on the Force.com platform without using HTTP callouts from Apex. The following documentation is available from developerforce.com: • • • Salesforce.com Spring ‘13 Release Notes—What’s new in Connect in Apex in Spring ‘13. Chatter REST API Developer’s Guide—The complete Connect in Apex documentation. Force.com Cookbook—Code recipes to get you started working with Connect in Apex. Apex Interfaces Apex provides the following system-defined interfaces: • Auth.RegistrationHandler Salesforce provides the ability to use an authentication provider, such as Facebook© or Janrain©, for single sign-on into Salesforce. To set up single sign-on, you must create a class that implements Auth.RegistrationHandler. Classes implementing the Auth.RegistrationHandler interface are specified as the Registration Handler in authorization provider definitions, and enable single sign-on into Salesforce portals and organizations from third-party services such as Facebook. • Comparable The Comparable interface adds sorting support for Lists that contain non-primitive types, that is, Lists of user-defined types. To add List sorting support for your Apex class, you must implement the Comparable interface with its compareTo method in your class. 562 Reference Apex Interfaces • Database.Batchable Batch Apex is exposed as an interface that must be implemented by the developer. Batch jobs can be programmatically invoked at runtime using Apex. • HttpCalloutMock Interface The HttpCalloutMock interface enables sending fake responses when testing HTTP callouts. • Iterator and Iterable An iterator traverses through every item in a collection. For example, in a while loop in Apex, you define a condition for exiting the loop, and you must provide some means of traversing the collection, that is, an iterator. • InstallHandler App developers can implement this interface to specify Apex code that runs automatically after a subscriber installs or upgrades a managed package. This makes it possible to customize the package install or upgrade, based on details of the subscriber’s organization. For instance, you can use the script to populate custom settings, create sample data, send an email to the installer, notify an external system, or kick off a batch operation to populate a new field across a large set of data. • Messaging.InboundEmailHandler For every email the Apex email service domain receives, Salesforce creates a separate InboundEmail object that contains the contents and attachments of that email. You can use Apex classes that implement the Messaging.InboundEmailHandler interface to handle an inbound email message. Using the handleInboundEmail method in that class, you can access an InboundEmail object to retrieve the contents, headers, and attachments of inbound email messages, as well as perform many functions. • • Process.Plugin is a built-in interface that allows you to process data within your organization and pass it to a specified flow. Schedulable To invoke Apex classes to run at specific times, first implement the Schedulable interface for the class, then specify the schedule using either the Schedule Apex page in the Salesforce user interface, or the System.schedule method. • Support.EmailTemplateSelector Interface The Support.EmailTemplateSelector interface enables providing default email templates in Case Feed. With default email templates, specified email templates are preloaded for cases based on criteria such as case origin or subject. • Site.UrlRewriter Create rules to rewrite URL requests typed into the address bar, launched from bookmarks, or linked from external websites. You can also create rules to rewrite the URLs for links within site pages. URL rewriting not only makes URLs more descriptive and intuitive for users, it allows search engines to better index your site pages. • UninstallHandler App developers can implement this interface to specify Apex code that runs automatically after a subscriber uninstalls a managed package. This makes it possible to perform cleanup and notification tasks based on details of the subscriber’s organization. • WebServiceMock Interface The WebServiceMock interface enables sending fake responses when testing Web service callouts of a class auto-generated from a WSDL. 563 Reference Auth.RegistrationHandler Interface Auth.RegistrationHandler Interface Salesforce provides the ability to use an authentication provider, such as Facebook© or Janrain©, for single sign-on into Salesforce. To set up single sign-on, you must create a class that implements Auth.RegistrationHandler. Classes implementing the Auth.RegistrationHandler interface are specified as the Registration Handler in authorization provider definitions, and enable single sign-on into Salesforce portals and organizations from third-party services such as Facebook. Using information from the authentication providers, your class must perform the logic of creating and updating user data as appropriate, including any associated account and contact records. Name Arguments Return Type User Description Returns a User object using the specified portal ID and user information from the third party, such as the username and email address. The User object corresponds to the third party’s user information and may be a new user that hasn’t been inserted in the database or may represent an existing user record in the database. The portalID value may be null or an empty key if there is no portal configured with this provider. updateUser ID userId createUser ID portalId Auth.UserData userData Void ID portalId Auth.UserData userData Updates the specified user’s information. This method is called if the user has logged in before with the authorization provider and then logs in again, or if your application is using the Existing User Linking URL. This URL is generated when you define your authentication provider. The portalID value may be null or an empty key if there is no portal configured with this provider. The Auth.UserData class is used to store user information for Auth.RegistrationHandler. The third-party authorization provider can send back a large collection of data about the user, including their username, email address, locale, and so on. Frequently used data is converted into a common format with the Auth.UserData class and sent to the registration handler. If the registration handler wants to use the rest of the data, the Auth.UserData class has an attributeMap variable. The attribute map is a map of strings (Map<String, String>) for the raw values of all the data from the third party. Because the map is <String, String>, values that the third party returns that are not strings (like an array of URLs or a map) are converted into an appropriate string representation. The map includes everything returned by the third-party authorization provider, including the items automatically converted into the common format. The constructor for Auth.UserData has the following syntax: Auth.UserData(String String String String String String String String String identifier, firstName, lastName, fullName, email, link, userName, locale, provider, 564 Reference Auth.RegistrationHandler Interface String siteLoginUrl, Map<String, String> attributeMap) The parameters for Auth.UserData are: Parameter identifier Type String String String String String String String String String String Map<String, String> Description An identifier from the third party for the authenticated user, such as the Facebook user number or the Salesforce user ID. The first name of the authenticated user, according to the third party. The last name of the authenticated user, according to the third party. The full name of the authenticated user, according to the third party. The email address of the authenticated user, according to the third party. A stable link for the authenticated user such as https://www.facebook.com/MyUsername. firstName lastName fullName email link username locale provider siteLoginUrl attributeMap The username of the authenticated user in the third party. The standard locale string for the authenticated user. The service used to log in, such as Facebook or Janrain. The site login page URL passed in if used with a site; null otherwise. A map of data from the third party, in case the handler has to access non-standard values. For example, when using Janrain as a provider, the fields Janrain returns in its accessCredentials dictionary are placed into the attributeMap. These fields vary by provider. Note: You can only perform DML operations on additional sObjects in the same transaction with User objects under certain circumstances. For more information, see sObjects That Cannot Be Used Together in DML Operations on page 276. For all authentication providers except Janrain, after a user is authenticated using a provider, the access token associated with that provider for this user can be obtained in Apex using the Auth.AuthToken Apex class. Auth.AuthToken provides two methods to retrieve access tokens. One is getAccessToken, which obtains a single access token. Use this method if the user ID is mapped to a single third-party user. If the user ID is mapped to multiple third-party users, use getAccessTokenMap, which returns a map of access tokens for each third-party user. For more information about authentication providers, see “About External Authentication Providers” in the Salesforce online help. When using Janrain as an authentication provider, you need to use the Janrain accessCredentials dictionary values to retrieve the access token or its equivalent. Only some providers supported by Janrain provide an access token, while other providers use other fields. The Janrain accessCredentials fields are returned in the attributeMap variable of the Auth.UserData class. See the Janrain auth_info documentation for more information on accessCredentials. Note: Not all Janrain account types return accessCredentials. You may need to change your account type to receive the information. 565 Reference Auth.RegistrationHandler Interface Name getAccessToken Arguments Return Type Description Returns an access token for the current user using the specified 18-character identifier of an Auth. Provider definition in your organization and the name of the provider, such as Salesforce or Facebook. token for the currently logged-in Salesforce user. The identifier value depends on the third party. For example, for Salesforce it would be the user ID, while for Facebook it would be the user number. String authProviderId String String providerName getAccessTokenMap String authProviderId Map<String, Returns a map from the third-party identifier to the access String providerName String> Example Implementations This example implements the Auth.RegistrationHandler interface that creates as well as updates a standard user based on data provided by the authorization provider. Error checking has been omitted to keep the example simple. global class StandardUserRegistrationHandler implements Auth.RegistrationHandler{ global User createUser(Id portalId, Auth.UserData data){ User u = new User(); Profile p = [SELECT Id FROM profile WHERE name='Standard User']; u.username = data.username + '@salesforce.com'; u.email = data.email; u.lastName = data.lastName; u.firstName = data.firstName; String alias = data.username; if(alias.length() > 8) { alias = alias.substring(0, 8); } u.alias = alias; u.languagelocalekey = data.locale; u.localesidkey = data.locale; u.emailEncodingKey = 'UTF-8'; u.timeZoneSidKey = 'America/Los_Angeles'; u.profileId = p.Id; return u; } global void updateUser(Id userId, Id portalId, Auth.UserData data){ User u = new User(id=userId); u.username = data.username + '@salesforce.com'; u.email = data.email; u.lastName = data.lastName; u.firstName = data.firstName; String alias = data.username; if(alias.length() > 8) { alias = alias.substring(0, 8); } u.alias = alias; u.languagelocalekey = data.locale; u.localesidkey = data.locale; update(u); } } The following example tests the above code. @isTest private class StandardUserRegistrationHandlerTest { 566 assertEquals('testFirst'. Lists of user-defined types. 'testNewLast'. email. updatedUser. updatedUser. u. handler.assertEquals('testnewu'.org'.firstName). 'testuser@example. 'testNewFirst testNewLast'.org'.com'.UserData sampleData = new Auth. sampleData = new Auth. The Comparable interface contains the following method.assertEquals('
[email protected]. User updatedUser = [SELECT userName. null. System. String uid = u.org'. sampleData).assertEquals('testuser'. null.email).lastName). Auth. System.lastName).assertEquals('testNewLast'.firstName). 'testFirst'.UserData('testNewId'. insert(u). you must implement the Comparable interface with its compareTo method in your class. u. null. 'testuserlong'.alias). u. alias FROM user WHERE id=:uid]. updatedUser. 'testLast'. 'en_US'. 'testFirst testLast'. System. System.createUser(null. null. null. new Map<String.org'.Reference Comparable Interface static testMethod void testCreateAndUpdateUser() { StandardUserRegistrationHandler handler = new StandardUserRegistrationHandler(). } } Comparable Interface The Comparable interface adds sorting support for Lists that contain non-primitive types. u.com'. String>{}). System. String>{}).assertEquals('testuserlong@salesforce. that is. System.UserData('testId'. System. To add List sorting support for your Apex class. 'testnewuser@example. you must first declare a class with the implements keyword as follows: global class Employee implements Comparable { 567 . User u = handler.assertEquals('testuser@example. lastName. firstName. 'testnewuserlong'. 'facebook'. 'testNewFirst'.assertEquals('testnewuserlong@salesforce. Name Arguments Return Type Description Returns an Integer value that is the result of the comparison.assertEquals('testLast'. updatedUser. System. 'en_US'. System.userName). sampleData). The implementation of this method should return the following values: • 0 if this instance and objectToCompareTo are equal • > 0 if this instance is greater than objectToCompareTo • < 0 if this instance is less than objectToCompareTo compareTo Object objectToCompareTo Integer To implement the Comparable interface. updatedUser. new Map<String. System.assertEquals('testNewFirst'.alias). u.email).updateUser(uid. 'facebook'.userName). global class Employee implements Comparable { public Long id. } // Implement the compareTo() method global Integer compareTo(Object compareTo) { Employee compareToEmp = (Employee)compareTo.Name). '4155551099')). // Sort using the custom compareTo() method empList. System. if (id == compareToEmp. System. This is an example implementation of the Comparable interface.'Caragh Smith'. String p) { id = i.id) return 0. 568 . public String phone. phone = p. System. return -1.assertEquals('Mario Ruiz'. The compareTo method in this example compares the employee of this class instance with the employee passed in the argument. System.Name). empList[3].add(new Employee(101. // Constructor public Employee(Long i.add(new Employee(25. // Verify list sort order. Smith'. empList.assertEquals('J.Reference Comparable Interface Next.'Joe Smith'. empList. String n.assertEquals('Caragh Smith'.sort().Name).Name). empList[1]. empList. your class must provide an implementation for the following method: global Integer compareTo(Object compareTo) { // Your code here } The implemented method must be declared as global or public. The method returns an Integer value based on the comparison of the employee IDs. empList[0].'J.'Mario Ruiz'. // Write list contents to the debug log System.assertEquals('Joe Smith'. public String name.add(new Employee(105. '4155551212')). '4155551000')).debug(empList). if (id > compareToEmp. empList. empList[2]. @isTest private class EmployeeSortingTest { static testmethod void test1() { List<Employee> empList = new List<Employee>(). } } This example tests the sort order of a list of Employee objects. '4155551212')).id) return 1. Smith'.add(new Employee(101. name = n. Reference HttpCalloutMock Interface } } See Also: List Methods HttpCalloutMock Interface The HttpCalloutMock interface enables sending fake responses when testing HTTP callouts. The InstallHandler interface has a single method called onInstall. not while running tests. and is subject to default governor limits. For an implementation example. send an email to the installer. If no user is specified. based on details of the subscriber’s organization. It runs as a special system user that represents your package. the install/upgrade details will be unavailable. The post install script has the following additional properties. scheduled. you can use the script to populate custom settings. The implementation of this method is called by the Apex runtime to send a fake response when an HTTP callout is made after Test. create sample data. This makes it possible to customize the package install or upgrade. The callout occurs after the script is run and the install is complete and committed. • • • It can initiate batch. and future jobs. It contains the following method. so all operations performed by the script appear to be done by your package. You will only see this user at runtime. For instance. Any errors in the script are emailed to the user specified in the Notify on Apex Error field of the package. which provides the following information. global interface InstallHandler { void onInstall(InstallContext context) }. Name respond Arguments HttpRequest req Return Type HttpResponse Description Returns an HTTP response for the given request. You can access this user by using UserInfo. The onInstall method takes a context object as its argument. or kick off a batch operation to populate a new field across a large set of data. If the script fails. InstallHandler Interface App developers can implement this interface to specify Apex code that runs automatically after a subscriber installs or upgrades a managed package. It can only perform callouts using an async operation. see Testing HTTP Callouts by Implementing the HttpCalloutMock Interface. It can’t access Session IDs. notify an external system. which specifies the actions to be performed on install/upgrade. 569 . The post install script is invoked after tests have been run. the install/upgrade is aborted.setMock has been called. global class PostInstallClass implements InstallHandler { global void onInstall(InstallContext context) { if(context. User u = [Select Id. If the upgrade is being pushed.'). The version number of the previously installed package (specified using the Version class).0. the script creates a new instance of Survey called “Upgrading from Version 1. called “Client Satisfaction Survey”. • • • If the previous version is 1. } else if(context.Email[] { mail }). such as 1. If the package is an upgrade. Messaging.sendEmail(new Messaging. Whether the installation is an upgrade. Version previousVersion().2.previousVersion(). mail. The following definition of the InstallContext interface shows the methods you can call on the context argument.SingleEmailMessage(). the script: ◊ Creates a new Account called “Newco” and verifies that it was created.setToAddresses(toAddresses). This is always a three-part number. String[] toAddresses = new String[]{toAddress}.0').SingleEmailMessage mail = new Messaging. ◊ Sends an email message to the subscriber confirming installation of the package. the script creates a new instance of Survey called “Sample Survey during Push”. • If the previous version is null. mail. Boolean isUpgrade(). The user ID of the user who initiated the installation. the script creates a new instance of Survey called “Sample Survey during Upgrade”. } if(context.compareTo(new Version(1. insert obj. that is.Email. mail. Whether the installation is a push. mail.Reference InstallHandler Interface • • • • • The org ID of the organization in which the installation takes place. insert(a).installerID()].setSubject('Package install successful'). global interface InstallContext { ID organizationId(). insert(obj). String toAddress= u.setReplyTo('
[email protected]').isUpgrade()) { 570 . Boolean isPush(). ◊ Creates a new instance of the custom object Survey. This interface is automatically implemented by the system.0”. Email from User where Id =:context. The context argument is an object whose type is the InstallContext interface. the package is being installed for the first time.previousVersion() == null) { Account a = new Account(name='Newco'). Survey__c obj = new Survey__c(name='Client Satisfaction Survey').0. mail.setSenderDisplayName('My Package Support'). Messaging.0)) == 0) { Survey__c obj = new Survey__c(name='Upgrading from Version 1. } Example of a Post Install Script The following sample post install script performs these actions on package install/upgrade.setPlainTextBody('Thanks for installing the package. ID installerId(). Reference Support. 1. A Version object that specifies the version number of the existing package. Example Implementation This is an example implementation of the Support. Name Arguments Return Type Description ID Returns the ID of the email template to preload for the case currently being viewed in the case feed using the specified case ID. • • • A class that implements the InstallHandler interface. List<Account> a = [Select id. global class MyCaseTemplateChooser implements Support. null). new Version(1.isPush()) { Survey__c obj = new Survey__c(name='Sample Survey during Push'). Next. it selects an email template based on the case subject and returns the email template ID.EmailTemplateSelector Interface The Support. insert obj.EmailTemplateSelector Interface Survey__c obj = new Survey__c(name='Sample Survey during Upgrade').0).EmailTemplateSelector. getDefaultTemplateId ID caseId When you implement this interface. } Support. The default is false. insert obj. } } } You can test a post install script using the new testInstall method of the Test class. @isTest static void testInstallScript() { PostInstallClass postinstall = new PostInstallClass(). The Support.EmailTemplateSelector interface enables providing default email templates in Case Feed. Test. An optional Boolean value that is true if the installation is a push. With default email templates.testInstall(postinstall.EmailTemplateSelector { // Empty constructor global MyCaseTemplateChooser() { } // The main interface method global ID getDefaultEmailTemplateId(ID caseId) { 571 . you must create a class that implements Support. System.EmailTemplateSelector interface. true). provide an empty parameterless constructor. Test.size(). This sample shows how to test a post install script implemented in the PostInstallClass Apex class.testInstall(postinstall.EmailTemplateSelector interface contains the following method. } if(context. specified email templates are preloaded for cases based on criteria such as case origin or subject. name from Account where name ='Newco'].assertEquals(a. The getDefaultEmailTemplateId method implementation retrieves the subject and description of the case corresponding to the specified case ID. This method takes the following arguments. To specify default templates. 'Account not found'). EmailTemplate et. or linked from external websites. c.force. Database. System.getDefaultEmailTemplateId(c.subject. URL rewriting not only makes URLs more descriptive and intuitive for users.subject.contains('LX-1220')) { et = [SELECT id FROM EmailTemplate WHERE DeveloperName = 'LX1220_template'].id.update(c).getDefaultEmailTemplateId(c. expectedTemplateId). You can also create rules to rewrite the URLs for links within site pages. Id expectedTemplateId = expectedTemplate. Description FROM Case WHERE Id=:caseId].com/posts?id=003D000000Q0PcN 572 .Reference Site.insert(c).Subject = 'My LX1220 is overheating'. it allows search engines to better index your site pages.UrlRewriter Interface Sites provides built-in logic that helps you display user-friendly URLs and links to site visitors.assertEquals(actualTemplateId. expectedTemplate = [SELECT id FROM EmailTemplate WHERE DeveloperName = 'LX1220_template'].Subject = 'I\'m having trouble with my LX-1150'. // Make sure the proper template is chosen for this subject Id actualTemplateId = chooser. expectedTemplateId = expectedTemplate. } else if(c. EmailTemplate expectedTemplate = [SELECT id FROM EmailTemplate WHERE DeveloperName = 'LX1150_template'].UrlRewriter Interface // Select the case we're interested in. launched from bookmarks.contains('LX-1150')) { et = [SELECT id FROM EmailTemplate WHERE DeveloperName = 'LX1150_template']. } } The following example tests the above code: @isTest private class MyCaseTemplateChooserTest { static testMethod void testChooseTemplate() { MyCaseTemplateChooser chooser = new MyCaseTemplateChooser().Id). a blog entry's URL might look like this: http://myblog.assertEquals(actualTemplateId.Id). // Create a simulated case to test with Case c = new Case(). if (c. let's say that you have a blog site.Id. } } Site. } // Return the ID of the template selected return et. Without URL rewriting. Create rules to rewrite URL requests typed into the address bar. // Change the case properties to match a different template c.Id. // Make sure the correct template is chosen in this case actualTemplateId = chooser. choosing any fields that are relevant to our decision Case c = [SELECT Subject. System. Database. For example. expectedTemplateId). Class Must Include Both Methods The Apex class must implement both the mapRequestUrl and generateUrlFor methods.force. The following are the instance methods for the Site.PageReference[] Return Type System.Reference Site. Name generateUrlFor Arguments System. } Consider the following restrictions and recommendations as you create your Apex class: Class and Methods Must Be Global The Apex class and methods must all be global. If your New Year's Eve post contained a link to your Valentine's Day post.UrlRewriter { global PageReference mapRequestUrl(PageReference yourFriendlyUrl) global PageReference[] generateUrlFor(PageReference[] yourSalesforceUrls).com/posts/2010/02/14/last-minute-roses To rewrite URLs for a site. which is part of Force.com sites. mapRequestUrl System.force.PageReference Maps a user-friendly URL to a Salesforce URL.UrlRewriter. If you don't want to use one of the methods. simply have it return null. the link URL might show: http://myblog. 573 .PageReference System. The generateUrlFor method maps input URLs to output URLs based on the order in the lists.com/posts/2009/12/31/auld-lang-syne You can also rewrite URLs for links shown within a site page. your users can access blog posts by date and title. if you prefer. create an Apex class that maps the original URLs to user-friendly URLs.PageReference[] Description Maps a list of Salesforce URLs to a list of user-friendly URLs. In general. The URL for one of your New Year's Eve posts might be: http://myblog. say. instead of by record ID. it must have the following form: global class yourClass implements Site. Important: The size and order of the input list of Salesforce URLs must exactly correspond to the size and order of the generated list of user-friendly URLs. Creating the Apex Class The Apex class that you create must implement the Force.UrlRewriter interface. and then add the Apex class to your site.UrlRewriter Interface With URL rewriting.com provided interface Site. You can use List<PageReference> instead of PageReference[]. You can't use periods in your rewritten URLs. or other entities. images. use the urlDecode method of the EncodingUtil class. For example. the following links to a Visualforce page named myPage: <apex:outputLink value="{!URLFOR($Page. You can't map to standard pages. To rewrite URLs for links on your site's pages. See the “Functions” appendix of the Visualforce Developer's Guide. Encoded URLs The URLs you get from using the Site.urlRewriter interface are encoded.Reference Site.UrlRewriter Interface Rewriting Only Works for Visualforce Site Pages Incoming URL requests can only be mapped to Visualforce pages associated with your site. URLs with a three-character entity prefix or a 15. use the !URLFOR function with the $Page merge variable.or 18-character ID are not rewritten.myPage)}"></apex:outputLink> Note: Visualforce <apex:form> elements with forceSSL=”true” aren't affected by the urlRewriter. Restricted Characters User-friendly URLs must be distinct from Salesforce URLs. Restricted Strings You can't use the following reserved strings as part of a rewritten URL path: • apexcomponent • apexpages • ex • faces • flash • flex • google • home • ideas • images • img • javascript • js • lumen • m • resource • search • secur • services • servlet • setup • sfc • sfdc_ns 574 . If you need to access the unencoded values of your URL. For example. Adding URL Rewriting to a Site Once you've created the URL rewriting Apex class. and myBlog is the value to look for: Site. title is the custom field name. where “help” is the site prefix.com/help. we have a simple site consisting of two Visualforce pages: mycontact and myaccount. Note: If you have URL rewriting enabled on your site. Each page uses the standard controller for its object type. follow these steps to add it to your site: 1. only /MyPage?id=12345 is returned. The resulting path. perform tasks in bulk rather than one at a time for the generateUrlFor method. if your URL is http://mycompany. all PageReferences are passed through the URL rewriter. The contact page includes a link to the parent account.force. mynamespace__Blog__c.fields.'myBlog'). Be sure you have “Read” permission enabled for both before trying the sample. Unique Paths Only You can't map a URL to a directory that has the same name as your site prefix. 4. For example. Using unique or indexed fields in SOQL for your queries may improve performance. Click Save. where mynamespace is the namespace. 575 .sObjectType.Reference Site. Click Your Name > Setup > Develop > Sites. Here is an example. Click New or click Edit for an existing site.com/sales/MyPage?id=12345.force. Code Example In this example. 2.getUrl method only returns the part of the URL immediately following the host name or site prefix (if any). where “sales” is the site prefix. plus contact details. otherwise it returns an error. http://acme.title__c. would be returned instead as http://acme.lookupIdByFieldValue method to look up records by a unique field name and value. if your site URL is http://acme.force. On the Site Edit page.com/help/help/page. choose an Apex class for URL Rewriter Class. You can't rewrite the domain or site prefix. you can't point the URL to help/page. The method verifies that the specified field has a unique or external ID. Blog is the custom object name.UrlRewriter Interface • • • • site style vote widg Relative Paths Only The pageReference. 3. You can also use the Site.lookupIdByFieldValue(Schema.com/help/page. Enforce Field Uniqueness Make sure the fields you choose for rewriting URLs are unique. Query in Bulk For better performance with page generation.force. String CONTACT_VISUALFORCE_PAGE = '/mycontact?id='. if(url. //Variables to represent my custom Visualforce pages //that display account and contact information String ACCOUNT_VISUALFORCE_PAGE = '/myaccount?id='. <apex:page standardController="Account"> <apex:detail relatedList="false"/> </apex:page> The contact page uses the standard controller for contacts and consists of two parts.length()). It also uses the generateUrlFor method to rewrite the URL for the link to the account page in a more user-friendly form.length(). Example Site Pages This section shows the Visualforce for the account and contact pages used in this example. <apex:page standardController="contact"> <apex:pageBlock title="Parent Account"> <apex:outputLink value="{!URLFOR($Page. The account page uses the standard controller for accounts and is nothing more than a standard detail page.id])}">{!contact. illustrated in the Figure 11: Site URLs Before Rewriting. the address bar and link URLs showed the record ID (a random 15-digit string).mycontact. The Apex class used to rewrite the URLs for these pages is shown in Example URL Rewriting Apex Class.Reference Site.UrlRewriter { //Variables to represent the user-friendly URLs for //account and contact pages String ACCOUNT_PAGE = '/myaccount/'.account.getUrl(). This page should be named myaccount. illustrated in the Figure 12: Site URLs After Rewriting. String CONTACT_PAGE = '/mycontact/'.startsWith(CONTACT_PAGE)){ //Extract the name of the contact from the URL //For example: /mycontact/Ryan returns Ryan String name = url. global with sharing class myRewriter implements Site. This page should be named mycontact.name} </apex:outputLink> </apex:pageBlock> <apex:detail relatedList="false"/> </apex:page> Example URL Rewriting Apex Class The Apex class used as the URL rewriter for the site uses the mapRequestUrl method to map incoming URL requests to the right Salesforce record.substring(CONTACT_PAGE. Once rewriting was enabled.null. with detailed comments. [id=contact. The first part links to the parent account using the URLFOR function and the $Page merge variable.UrlRewriter Interface Before implementing rewriting. the address bar and links show more user-friendly rewritten URLs.account. //Select the ID of the contact that matches //the name from the URL Contact con = [SELECT Id FROM Contact WHERE Name =: 576 . the second simply provides the contact details. Notice that the Visualforce page doesn't contain any rewriting logic except URLFOR. global PageReference mapRequestUrl(PageReference myFriendlyUrl){ String url = myFriendlyUrl. url. //don't do any transformations myFriendlyUrls. url.add(id).length()).startsWith(ACCOUNT_PAGE)){ //Extract the name of the account String name = url.startsWith(ACCOUNT_VISUALFORCE_PAGE)){ myFriendlyUrls. transform it if(url. //a list of all the ids in the urls List<id> accIds = new List<id>().Reference Site. finding all the valid ids for(PageReference mySalesforceUrl : mySalesforceUrls){ //Get the URL of the page String url = mySalesforceUrl. } global List<PageReference> generateUrlFor(List<PageReference> mySalesforceUrls){ //A list of pages to return after all the links //have been evaluated List<PageReference> myFriendlyUrls = new List<PageReference>(). // loop through all the urls once.length()). for(PageReference mySalesforceUrl : mySalesforceUrls) { //Get the URL of the page String url = mySalesforceUrl. //Construct a new page reference in the form //of my Visualforce page return new PageReference(CONTACT_VISUALFORCE_PAGE + con. //If this looks like an account page. continue with the request return null.id). String id= url.getUrl(). // make the new urls Integer counter = 0.substring(ACCOUNT_PAGE. } //If the URL isn't in the form of a contact or //account page.substring(ACCOUNT_VISUALFORCE_PAGE.length().add(new PageReference(ACCOUNT_PAGE + accounts.startsWith(ACCOUNT_VISUALFORCE_PAGE)){ //Extract the ID from the query parameter //and store in a list //for querying later in bulk.UrlRewriter Interface name LIMIT 1].name)). // it is important to go through all the urls again. if(url. } 577 . } } // Get all the account names in bulk List <account> accounts = [SELECT Name FROM Account WHERE Id IN :accIds]. so that the order // of the urls in the list is maintained. //Return a page in Visualforce format return new PageReference(ACCOUNT_VISUALFORCE_PAGE + acc.add(mySalesforceUrl).length(). accIds. url. //Query for the ID of an account with this name Account acc = [SELECT Id FROM Account WHERE Name =:name LIMIT 1].id).get(counter).getUrl(). } if(url. counter++. } else { //If this doesn't start like an account page. } } Before and After Rewriting Here is a visual example of the results of implementing the Apex class to rewrite the original site URLs.UrlRewriter Interface } //Return the full list of pages return myFriendlyUrls. The original URL for the contact page before rewriting 2. Figure 11: Site URLs Before Rewriting The numbered elements in this figure are: 1. The original URL for the link to the account page before rewriting. and the user-friendly URLs in the second. The link to the parent account page from the contact page 3. shown in the browser's status bar 578 .Reference Site. Notice the ID-based URLs in the first figure. PluginDescribeResult class is used to determine the input parameters and output parameters needed by the Process.PluginRequest class passes input parameters from the class that implements the interface to the flow.Plugin interface in your organization. The rewritten URL for the contact page after rewriting 2. see Process. Process.Plugin Interface Figure 12: Site URLs After Rewriting The numbered elements in this figure are: 1. You must also create a map and use it in the constructor to pass in the parameters needed by the system.Reference Using the Process.PluginResult Process. The link to the parent account page from the contact page 3. the Cloud Flow Designer displays the Apex class in the Palette. The Process. shown in the browser's status bar Using the Process. For more information.PluginResult plug-in. When you define an Apex class that implements the Process.PluginResult class returns output parameters from the class that implements the interface to the flow.PluginDescribeResult The Process. The interface exposes Apex as a service. When you’re writing Apex unit tests.PluginRequest Class.PluginRequest Process.Plugin has the following top level classes: • • • Process. you must instantiate a class and pass it in the interface invoke method.Plugin is a built-in interface that allows you to process data within your organization and pass it to a specified flow. The rewritten URL for the link to the account page after rewriting. which accepts input values and returns output back to the flow.Plugin Interface Process. The Process. 579 .PluginRequest class passes input parameters from a flow to the class that implements the interface. The Process. fItem.Object> result = new Map<String. Process.STRING. global Process. result. // return to Flow Map<String.InputParameter>{ new Process. insert fItem. result.PluginResult Primary method that the system invokes when the class that implements the interface is instantiated.Plugin interface: Name describe Arguments Return Type Description Process.Plugin Interface Process.Plugin Interface Process.PluginRequest Process. // Use the Chatter APIs to post it to the current user's feed FeedItem fItem = new FeedItem().OutputParameter>{ }.PluginDescribeResult.Body = 'Force.PluginResult invoke(Process.PluginDescribeResult describe() { Process.PluginDescribeResult Returns a Process. return new Process.com flow Update: ' + subject.PluginDescribeResult. fItem. result. The Flow calls this at runtime.inputParameters.PluginDescribeResult result = new Process.InputParameter('subject'.Reference Using the Process.inputParameters = new List<Process. } // Returns the describe information for the interface global Process. The following are the methods that must be called by the class that implements the Process.PluginDescribeResult(). Example Implementation global class flowChat implements Process.Tag = "chat".PluginDescribeResult. return result.PluginResult(result).getUserId(). true) }.ParameterType.get('subject').Object>().Plugin is a built-in interface that allows you to pass data between your organization and a specified flow. result.Name = "flowchatplugin". invoke Process.PluginDescribeResult object that describes this method call.PluginRequest request) { // Get the subject of the Chatter post from the flow String subject = (String) request.ParentId = UserInfo.Plugin { // The main method to be implemented. } } 580 .PluginDescribeResult.outputParameters = new List<Process. PluginDescribeResult describe() { Process.PluginRequest class with one input parameter: Map<String.put('subject'. fpost. the code returns the subject of a Chatter post from a flow and posts it to the current user's feed.Object> result = new Map<String.Body = 'Force. fpost.PluginRequest request = new Process.PluginRequest class passes input parameters from the class that implements the interface to the flow. This class has no methods. InputParams. } } Process.invoke(request).Object>) The following is an example of instantiating the Process. feedSubject).ParentId = UserInfo.PluginRequest (Map<String. // return to Flow Map<String. } // describes the interface global Process.Plugin Interface Test Class The following is a test class for the above class.PluginDescribeResult().Object> inputParams = new Map<String.PluginRequest request) { // Get the subject of the Chatter post from the flow String subject = (String) request.getUserId(). @isTest private class flowChatTest { static testmethod void flowChatTests() { flowChat plugin = new flowChat(). plugin. Process. string feedSubject = 'Flow is alive'. // Use the Chatter APIs to post it to the current user's feed FeedPost fpost = new FeedPost(). 581 . string feedSubject = 'Flow is alive'. feedSubject).put('subject'.Object>().PluginRequest request = new Process. Map<String. return new Process. Code Example In this example.PluginRequest(inputParams).Object> inputParams = new Map<String.PluginResult invoke(Process.PluginDescribeResult result = new Process.Object>(). Constructor signature: Process.inputParameters.com flow Update: ' + subject.get('subject').PluginRequest(inputParams). Process.PluginRequest Class The Process.Reference Using the Process. insert fpost. InputParams.Object>().PluginResult(result). global Process. Map<String. return result.Plugin Interface result.STRING.Plugin interface describe method to dynamically provide both input and output parameters for the flow.PluginDescribeResult class can't be used to do the following functions: • • • • Queries Data modification Email Apex nested callouts Process. new Process.PluginDescribeResult Properties Name Description Type String Description This optional field describes the purpose of the plug-in. } } Process.PluginResult class.PluginResult class using one of the following formats: • • Process.put('status'. url).PluginDescribeResult.PluginDescribeResult.PluginDescribeResult class is used to determine the input parameters and output parameters needed by the Process.status).PluginResult (Map<String.Reference Using the Process.PluginResult class. true) }. String status = 'Success'.PluginDescribeResult.Object>().inputParameters = new List<Process.InputParameter>{ new Process.put('url'.ParameterType.google.com/document/edit?id=abc'. result. This method returns the Process.Object> result = new Map<String.PluginResult class returns output parameters from the class that implements the interface to the flow. Size limit 255 characters 582 . Use the Process.OutputParameter>{ }. The following is an example of instantiating a Process. Process. string url = 'https://docs.PluginResult(result).PluginResult Class The Process. Process.PluginDescribeResult.InputParameter('subject'.Object>) Process. You can instantiate the Process. Object) Use the map when you have more than one result or when you don't know how many results will be returned. result.PluginDescribeResult Class The Process.outputParameters = new List<Process.PluginDescribeResult class.PluginResult (String.PluginDescribeResult Class and Subclass Properties Table 3: Process. The Process. result. PluginRequest class from a flow to the class that implements the Process. OutputParameter> Tag String With this optional field. ParameterType Required Boolean Set to true for required and false otherwise.Reference Using the Process.Plugin interface. Boolean_required).ParameterType.PluginDescribeResult.InputParameter Properties Name Description Name ParameterType Type String String Description This optional field describes the purpose of the plug-in.PluginResult class from the class that implements the Process. Table 5: Process.PluginDescribeResult.PluginDescribeResult. InputParameter> Name String 40 characters OutputParameters List <Process. Unique name of the plug-in.Plugin Interface Name Type Description The input parameters passed by the Process.Optional_description_string. Size limit 255 characters 40 characters Process.PluginDescribeResult. The data type of the input parameter. Table 4: Process.PluginDescribeResult.OutputParameter Properties Name Description Type String Description This optional field describes the purpose of the plug-in.PluginDescribeResult. Size limit 255 characters 583 .PluginDescribeResult class: Process. The following is the constructor for the Process.InputParameter ip = new Process.PluginDescribeResult.Enum. Process.InputParameter class: Process.PluginDescribeResult classname = new Process.InputParameter(Name.PluginDescribeResult(). The following is the constructor of the Process.PluginDescribeResult.Plugin interface to the flow. The output parameters passed by the Process. Unique name of the plug-in.PluginDescribeResult. This is helpful if you have multiple plug-ins in your flow. Size limit InputParameters List <Process. you can group 40 plug-ins by tag name so they appear together characters in the Apex plug-in section of the Palette within the Flow Designer. InputParameter Process.PluginDescribeResult.Optional description string.Optional description string.PluginDescribeResult.PluginDescribeResult.PluginDescribeResult.PluginDescribeResult class. which has the following values: 584 . Process. Size limit 40 characters Process.setTag ('userinfo').PluginDescribeResult.PluginDescribeResult. Process.ParameterType. result. create instances of the following additional subclasses: • • Process.STRING.OutputParameter('URL'.PluginDescribeResult().Enum.Plugin Interface Name Name ParameterType Type String Description Unique name of the plug-in. The following is the constructor of the Process.InputParameter>{ new Process.OutputParameter class: Process.OutputParameter(Name.setDescription('this plugin gets the name of a user').PluginDescribeResult. Process.outputParameters = new List<Process.Optional_description_string.PluginDescribeResult.ParameterType Enum.PluginDescribeResult. Process.PluginDescribeResult. Process.Enum).PluginDescribeResult. }.PluginDescribeResult.PluginDescribeResult.inputParameters = new List<Process.DATE.ParameterType.PluginDescribeResult.OutputParameter op = new new Process.InputParameter is a list of input parameters and has the following format: Process. Boolean_required) For example: Process.PluginDescribeResult.InputParameter>{ new Process.Enum) For example: Process.PluginDescribeResult.PluginDescribeResult.PluginDescribeResult. true).STRING). result.OutputParameter Process. true).ParameterType.setTag ('userinfo').ParameterType. To use the Process.OutputParameter(Name.PluginDescribeResult.PluginDescribeResult.ParameterType.PluginDescribeResult.PluginDescribeResult.PluginDescribeResult result = new Process. result.inputParameters = new List<Process.ParameterType The data type of the input parameter. Process.OutputParameter is a list of output parameters and has the following format: Process.ParameterType.InputParameter('DOB'. result.PluginDescribeResult.PluginDescribeResult.InputParameter('FullName'.PluginDescribeResult.setDescription('this plugin gets the name of a user').outputParameters = new List<Process.Reference Using the Process. result.OutputParameter>{ new Process.InputParameter(Name. new Process. Process. Both classes take the Process.PluginDescribeResult.OutputParameter>{ new Process. result.PluginDescribeResult result = new Process.PluginDescribeResult(). This implementation can be called from a flow via an Apex plug-in element. // Converts a lead as a step in a Visual Workflow process.PluginRequest request) { // Set up variables to store input parameters from // the flow. Test methods for the plug-in are also included. and optionally. Process.Plugin interface and converts a lead into an account. String leadID = (String) request.PluginDescribeResult.PluginDescribeResult().OutputParameter('STATUS'.PluginDescribeResult result = new Process.inputParameters.Plugin { // This method runs when called by a flow's Apex plug-in element.get( 'LeadID'). Process.PluginDescribeResult.Plugin Implementation for Lead Conversion In this example.Plugin Interface • • • • • • • • • • BOOLEAN DATE DATETIME DECIMAL DOUBLE FLOAT ID INTEGER LONG STRING For example: Process. an Apex class implements the Process.STRING.PluginDescribeResult.outputParameters = new List<Process. an opportunity.ParameterType. String contactID = (String) 585 .PluginDescribeResult. new Process. Flow Data Type Number Date Boolean Text Data Type Decimal Datetime/Date Boolean and numeric with 1 or 0 values only String Sample Process.OutputParameter>{ new Process.PluginResult invoke( Process. Process.ParameterType.Plugin. text data in a flow converts to string data in Apex. global class VWFConvertLead implements Process. true).PluginDescribeResult. contact. global Process. result.Reference Using the Process.STRING).OutputParameter('URL'.Plugin Data Type Conversions The following shows the data type conversions between Apex and the values returned to the Process. }. For example. } // This method describes the plug-in and its inputs from // and outputs to the flow. String accountID = (String) request. true).get('CreateOpportunity'). false).inputParameters.inputParameters.'.PluginDescribeResult result = new Process. opportunityName.PluginDescribeResult.inputParameters = new List<Process.inputParameters.InputParameter( 'ContactID'.) are // supported at this time. result. Process.PluginDescribeResult. // Create a list that stores both mandatory and optional // input parameters from the flow.InputParameter>{ // Lead ID (mandatory) new Process.Reference Using the Process.STRING.PluginDescribeResult. String opportunityName = (String) request. 586 .description = 'The LeadConvert Flow Plug-in converts a lead into ' + 'an account. result. Boolean overWriteLeadSource = (Boolean) request. global Process. if (overWriteLeadSource == null) overWriteLeadSource = false. contactID.STRING.ParameterType.get('SendEmailToOwner'). result = convertLead(leadID.tag = 'Lead Management'. return new Process.inputParameters.get('OverwriteLeadSource'). sendEmailToOwner).PluginDescribeResult describe() { // Set up plugin metadata Process.PluginDescribeResult().PluginDescribeResult. String convertedStatus = (String) request.inputParameters.get('ContactID').get('ConvertedStatus').InputParameter( 'LeadID'. and ' + '(optionally)an opportunity.ParameterType. if (sendEmailToOwner == null) sendEmailToOwner = false.PluginDescribeResult.get('AccountID'). a contact. result. // Account Id (optional) new Process. convertedStatus.Object>(). NUMBER. etc. Process. Boolean createOpportunity = (Boolean) request. // Set the default handling for booleans. Map<String. // Collections are currently not supported. accountID. Process.get('ContactID').PluginDescribeResult. overWriteLeadSource. // Implementing this method adds the class to the // Cloud Flow Designer palette. Boolean sendEmailToOwner = (Boolean) request.ParameterType.Plugin Interface request. createOpportunity. if (createOpportunity == null) createOpportunity = true. // Contact ID (optional) new Process.STRING.InputParameter( 'AccountID'.Object> result = new Map<String.inputParameters.PluginResult(result).inputParameters.PluginDescribeResult. // NOTE: Only primitive types (STRING. // Convert the lead by passing it to a helper method. PluginDescribeResult. 587 .Name of the new Opportunity.PluginDescribeResult. // Opportunity ID of the converted lead new Process.true if you want to create a new * Opportunity upon conversion * opportunityName .InputParameter( 'ConvertedStatus'.ParameterType.InputParameter( 'OverwriteLeadSource'. * sendEmailtoOwner . // Contact ID of the converted lead new Process. } /** * Implementation of the LeadConvert plug-in.ParameterType. * OpportunityID .OutputParameter( 'ContactID'.PluginDescribeResult. true).BOOLEAN.BOOLEAN.ParameterType.PluginDescribeResult.PluginDescribeResult. new Process.PluginDescribeResult.ParameterType. Process.PluginDescribeResult.InputParameter( 'CreateOpportunity'. false). // Create a list that stores output parameters sent // to the flow.outputParameters = new List< Process.ID of the Opportunity created * upon conversion. Process.Plugin Interface false).PluginDescribeResult.OutputParameter( 'OpportunityID'.STRING).STRING.ID of the Contact created or attached * to upon conversion. new Process.true if you are changing owners upon * conversion and want to notify the new Opportunity owner.STRING.OutputParameter>{ // Account ID of the converted lead new Process. new Process. Process.ParameterType.ParameterType.ParameterType.ID of the Account created or attached * to upon conversion. false). // Status to use once converted new Process.PluginDescribeResult.PluginDescribeResult. return result. Process. Process.ID of the lead to convert * contactID * accountID . * convertedStatus * overWriteLeadSource * createOpportunity . Process. new Process. * Converts a given lead with several options: * leadID .STRING) }. Process. * * returns: a Map with the following output: * AccountID . * ContactID . false) }.Reference Using the Process.BOOLEAN.InputParameter( 'SendEmailToOwner'.PluginDescribeResult.PluginDescribeResult.PluginDescribeResult.PluginDescribeResult.ID of the Account to attach the converted * Lead/Contact/Opportunity to.PluginDescribeResult.ParameterType. result.PluginDescribeResult.OutputParameter( 'AccountID'. Process. false).InputParameter( 'OpportunityName'.PluginDescribeResult.STRING). if (createOpportunity) { result. checkContact = false if (accountID == null && l.setContactId(contactId).String> result = new Map<String. } return result. // check for multiple leads with the same ID Lead[] leads = [Select Id. true).setLeadId(leadID). if (accounts. Boolean createOpportunity.setOpportunityName(opportunityName).id.LeadConvert(). String opportunityName.getOpportunityId()). lc. if (contactId != null && contactId.setDoNotCreateOpportunity(!createOpportunity). } } // Perform the lead conversion.setSendNotificationEmail( sendEmailToOwner). result.length() > 0) lc.length() > 0) lc. Boolean overWriteLeadSource.getContactId()). lc. } } else { throw new ConvertLeadPluginException( 'No leads found with Id : "' + leadId + '"').Company != null) { Account[] accounts = [Select Id. } } else { String error = lcr.getMessage(). Company From Lead where Id = :leadID]. lc. if (leads. // CheckAccount = true. String accountID. if (lcr. Database.getAccountId()).setConvertedStatus(convertedStatus). } // Utility exception class 588 .put('OpportunityID'.setOverwriteLeadSource(overWriteLeadSource). LastName.setAccountId(accountId). } Database.convertLead( lc.Plugin Interface */ public Map<String. throw new ConvertLeadPluginException(error).String> convertLead ( String leadID. String convertedStatus. String contactID.put('AccountID'.getErrors()[0].Reference Using the Process. if (accountId != null && accountId. Name FROM Account where Name = :l.String>(). if (sendEmailToOwner != null) lc. lcr.Company LIMIT 1].LeadConvertResult lcr = Database. lcr. Boolean sendEmailToOwner ) { Map<String.size() > 0) { Lead l = leads[0]. lcr. if (createOpportunity) { lc.size() > 0) { accountId = accounts[0]. if (leadId == null) throw new ConvertLeadPluginException( 'Lead Id cannot be null'). FirstName.LeadConvert lc = new Database.put('ContactID'. lc.isSuccess()) { result. convertStatus.MasterLabel). id.LastName='Doe').Plugin Interface class ConvertLeadPluginException extends Exception {} static testMethod void basicTest() { // Create test lead Lead testLead = new Lead( Company='Test Lead'. */ static testMethod void basicTestwithAccount() { // Create test lead Lead testLead = new Lead( Company='Test Lead'.put('ConvertedStatus'.Reference Using the Process.PluginRequest request = new Process. Process.testAccount. isConverted from Lead where id = :testLead.ID).isConverted).FirstName='John'.invoke(request). inputParams. convertStatus.PluginRequest(inputParams).Object> inputParams = new Map<String.Object> inputParams = new Map<String. Map<String.PluginResult result. // Create test conversion VWFConvertLead aLeadPlugin = new VWFConvertLead(). Lead aLead = 589 .ID).Object> outputParams = new Map<String.testLead. } /* * This tests lead conversion with * the Account ID specified.Object>().Object> outputParams = new Map<String. Process. Process.FirstName='John'. System.PluginResult result. Map<String. LeadStatus convertStatus = [Select Id. inputParams.put('LeadID'. result = aLeadPlugin.Assert(aLead. inputParams. Account testAccount = new Account(name='Test Account'). Lead aLead = [select name.invoke(request). inputParams. MasterLabel from LeadStatus where IsConverted=true limit 1]. insert testAccount.Object>().PluginRequest request = new Process. MasterLabel from LeadStatus where IsConverted=true limit 1].put('AccountID'. Map<String.testLead.PluginRequest(inputParams).put('LeadID'.LastName='Doe'). Map<String.put('ConvertedStatus'.ID).Object>(). inputParams. // System.ID]. LeadStatus convertStatus = [Select Id. Process. // Create test conversion VWFConvertLead aLeadPlugin = new VWFConvertLead().Object>().ID).debug('ACCOUNT BEFORE' + testAccount. insert testLead. insert testLead.MasterLabel). result = aLeadPlugin. aLead. } /* * -ve Test */ static testMethod void errorTest() { // Create test lead // Lead testLead = new Lead(Company='Test Lead'.'00Q7XXXXxxxxxxx'). // System.convertStatus. System.ID].put('LeadID'.Object>().Object> outputParams = new Map<String. isConverted.testLead.MasterLabel). Lead aLead = [select name.LastName='Doe'). inputParams.PluginResult result. inputParams. // FirstName='John'.ID]. Process.put('LeadID'. Map<String.Assert(aLead.Assert(aLead.isConverted).PluginRequest request = new Process. result = aLeadPlugin.isConverted). System. Map<String.convertedAccountID). System. insert testAccount1.Object>(). LeadStatus convertStatus = [Select Id.Object> outputParams = new Map<String. } /* * This tests lead conversion with the Account ID specified.MasterLabel). id. Process.invoke(request). Map<String.ID).convertedAccountID). insert testAccount2.Object>(). MasterLabel from LeadStatus where IsConverted=true limit 1]. Process. inputParams. // Create test conversion VWFConvertLead aLeadPlugin = new VWFConvertLead(). MasterLabel from LeadStatus where IsConverted=true limit 1].debug('ACCOUNT AFTER' + aLead.Object> inputParams = new Map<String. Map<String. */ static testMethod void basicTestwithAccounts() { // Create test lead Lead testLead = new Lead( Company='Test Lead'. // Create test conversion VWFConvertLead aLeadPlugin = new VWFConvertLead(). id. convertedAccountID from Lead where id = :testLead.LastName='Doe'). Account testAccount2 = new Account(name='Test Lead'). convertStatus.put('ConvertedStatus'. insert testLead. isConverted.PluginRequest request = new 590 . convertedAccountID from Lead where id = :testLead.Object> inputParams = new Map<String.Plugin Interface [select name. //System.ID). Account testAccount1 = new Account(name='Test Lead'). LeadStatus convertStatus = [Select Id.ID.put('ConvertedStatus'.Object>().AssertEquals(testAccount.debug('ACCOUNT BEFORE' + testAccount.PluginRequest(inputParams).Reference Using the Process.FirstName='John'. inputParams. or to perform callouts.OutputParameters. 3). System. Process.Reference UninstallHandler Interface Process.AssertEquals( result. so all operations performed by the script will appear to be done by your package. You can’t use it to initiate batch. to access Session IDs. If the script fails.PluginRequest(inputParams). System.Plugin Interface Process. } catch (Exception e) { System. the uninstall details will be unavailable.AssertEquals(1. The uninstall script has the following restrictions. } } See Also: Using the Process.Plugin Interface Process.PluginResult Class Process. the uninstall continues but none of the changes performed by the script are committed.invoke(request).PluginDescribeResult Class UninstallHandler Interface App developers can implement this interface to specify Apex code that runs automatically after a subscriber uninstalls a managed package. Any errors in the script are emailed to the user specified in the Notify on Apex Error field of the package.describe().PluginResult result.PluginDescribeResult result = aLeadPlugin.size().debug('EXCEPTION' + e).size(). The uninstall script is subject to default governor limits. If no user is specified. 8). System. You can access this user by using UserInfo.1). This makes it possible to perform cleanup and notification tasks based on details of the subscriber’s organization. not while running tests. try { result = aLeadPlugin.inputParameters. scheduled. and future jobs.AssertEquals( result. It runs as a special system user that represents your package. You will only see this user at runtime.PluginRequest Class Process. Process. } } /* * This tests the describe() method */ static testMethod void describeTest() { VWFConvertLead aLeadPlugin = new VWFConvertLead(). 591 . '). This method takes as its argument a class that implements the UninstallHandler interface. • • Inserts an entry in the feed describing which user did the uninstall and in which organization Creates and sends an email message confirming the uninstall to that user global class UninstallClass implements UninstallHandler { global void onUninstall(UninstallContext ctx) { FeedItem feedPost = new FeedItem(). Messaging. String[] toAddresses = new String[] {toAddress}. This interface is automatically implemented by the system. • • The org ID of the organization in which the uninstall takes place. List<FeedItem> feedPostsBefore = [SELECT Id FROM FeedItem WHERE parentId=:UninstallerId AND CreatedDate=TODAY].sendEmail(new Messaging. global interface UninstallHandler { void onUninstall(UninstallContext context)}.setSenderDisplayName('My Package Support').testUninstall(new UninstallClass()). mail.Email. This sample shows how to test an uninstall script implemented in the UninstallClass Apex class.Email[] { mail }). which specifies the actions to be performed on uninstall. String toAddress= u.setToAddresses(toAddresses). feedPost.setReplyTo('support@package. Test.setSubject('Package uninstall successful').uninstallerID()].Reference UninstallHandler Interface The UninstallHandler interface has a single method called onUninstall. User u = [Select Id. mail. mail. insert feedPost. global interface UninstallContext { ID organizationId(). Email from User where Id =:ctx.uninstallerID().parentId = ctx.getUserId(). 592 .body = 'Thank you for using our application!'. The context argument is an object whose type is the UninstallContext interface. ID uninstallerId(). } Example of an Uninstall Script The sample uninstall script below performs the following actions on package uninstall.SingleEmailMessage mail = new Messaging.dev'). @isTest static void testUninstallScript() { Id UninstallerId = UserInfo. The onUninstall method takes a context object as its argument. } } You can test an uninstall script using the testUninstall method of the Test class. feedPost.setPlainTextBody('Thanks for uninstalling the package.SingleEmailMessage(). Messaging. The following definition of the UninstallContext interface shows the methods you can call on the context argument. The user ID of the user who initiated the uninstall. mail. which provides the following information. mail. • responseNS: The response namespace. see Testing Web Service Callouts on page 248. 'Post to uninstaller failed. Arguments: • stub: An instance of the auto-generated class. It contains the following method.setMock has been called.size() + 1. • response: A collection of key/value pairs representing the response to send for the request. set the response argument to a key/value pair representing the response desired. Object> response Return Type Void Description The implementation of this method is called by the Apex runtime to send a fake response when a Web service callout is made after Test. } WebServiceMock Interface The WebServiceMock interface enables sending fake responses when testing Web service callouts of a class auto-generated from a WSDL. String endpoint String soapAction String requestName String responseNS String responseName String responseType For an implementation example. • endpoint: The endpoint URL for the request. • soapAction: The requested SOAP operation.size(). 593 . • responseType: The class for the response as defined in the auto-generated class. Name doInvoke Arguments Object stub Object request Map<String. feedPostsAfter. • requestName: The requested SOAP operation name. • responseName: The name of the response element as defined in the WSDL.Reference WebServiceMock Interface List<FeedItem> feedPostsAfter = [SELECT Id FROM FeedItem WHERE parentId=:UninstallerId AND CreatedDate=TODAY]. When implementing this interface. • request: The SOAP Web service request being invoked.').assertEquals(feedPostsBefore. System. Live users accessing the system while you're developing can destabilize your data or corrupt your application. You can deploy Apex using: • • • • Change Sets the Force.com IDE the Force. • • • • Using Change Sets To Deploy Apex Using the Force.Chapter 14 Deploying Apex In this chapter .com IDE to Deploy Apex Using the Force.com Migration Tool SOAP API Any deployment of Apex is limited to 5. 594 .000 code units of classes and triggers. we recommend that you do all your development work in either a sandbox or a Developer Edition organization. Instead...com Migration Tool Using SOAP API to Deploy Apex You can't develop Apex in your Salesforce production organization. You can create an outbound change set in the Salesforce user interface and add the Apex components that you would like to upload and deploy to the target organization.com Master Subscription Agreement. Unlimited.com IDE to a Salesforce organization. Test methods and test classes are not counted as part of Apex code coverage.com application development. see “Change Sets” in the Salesforce online help. Note the following. All classes and triggers must compile successfully.com to support its users and partners but isn't considered part of our services for purposes of the salesforce. To deploy Apex from a local project in the Force. for example. every unit test in your organization namespace is executed. The Force. Designed for developers and development teams. This should lead to 75% or more of your code being covered by unit tests. including source code editors. Note: The Force. Calls to System. outline view. This tool includes basic color-coding. you should make sure that every use case of your application is covered. integrated unit testing. ◊ ◊ ◊ ◊ When deploying to a production organization.com IDE is a plug-in for the Eclipse IDE. Using the Force. and all of those tests must complete successfully.Deploying Apex Using Change Sets To Deploy Apex Using Change Sets To Deploy Apex Available in Enterprise. and auto-compilation on save with error message display. test execution tools.com IDE is a free resource provided by salesforce.com IDE” in the Force. For more information on how to use the Deploy to Server wizard.com IDE documentation. Instead. use the Deploy to Server wizard. from a sandbox organization to your production organization. • • Every trigger must have some test coverage.com IDE provides a unified interface for building and deploying Force. To learn more about change sets.debug are not counted as part of Apex code coverage. the IDE provides tools to accelerate Force. wizards and integrated help. 595 . your focus shouldn't be on the percentage of code that is covered. While only 75% of your Apex code must be covered by tests. Note: If you deploy to a production organization: • At least 75% of your Apex code must be covered by unit tests. and Database.com IDE to Deploy Apex The Force.com applications.com Editions You can deploy Apex classes and triggers between connected organizations. including positive and negative cases. see “Deploying Code with the Force. which is available within Eclipse. as well as bulk and single record. 596 . Visit http://java. Download the Force.user and sf.com Migration Tool Using the Force. you can also use a script to deploy Apex.Deploying Apex Using the Force. Edit the build.com production organization using Apache's Ant build tool.1 or greater on the deployment machine.6 or greater on the deployment machine.com Migration Tool is a free resource provided by salesforce.com Migration Tool. JAVA_HOME.0 compiled on December 13 2006 5. in order to run the sample ant tasks in build. Version 6. Version 1. The ant lib directory is located in the root folder of your Ant installation. 6.com IDE.properties file that you must edit.jar A sample folder containing: ◊ ◊ ◊ ◊ ◊ A codepkg\classes folder that contains SampleDeployClass. To use the Force.sun.jar file from the unzipped file into the ant lib directory. Note: The Force.html.org/manual/install.jsp and install Java JDK.apache.trigger A mypkg\objects folder that contains the custom objects used in the examples A removecodepkg folder that contains XML files for removing the examples from your organization A sample build. and entering ant –version. Copy the ant-salesforce.xml ◊ A sample build.com Migration Tool if you want to use a script for deploying Apex from a Developer Edition or sandbox organization to a Database.org/ and install Apache Ant. 9. that exercises the deploy and retrieve API calls 7. Open the sample subdirectory in the unzipped file. 2.7. do the following: 1.xml file.com to support its users and partners but isn't considered part of our services for purposes of the salesforce. and PATH) as specified in the Ant Installation Guide at http://ant. then click Force. Unzip the downloaded file to the directory of your choice. Log in to Salesforce on your deployment machine. 4. Set up the environment variables (such as ANT_HOME.com/javase/downloads/index.com Migration Tool. Enter your Salesforce production organization username and password for the sf.cls and SampleFailingTestClass. 3. Your output should look something like this: Apache Ant version 1. 8.com Master Subscription Agreement. Note: • The username you specify should have the authority to edit Apex.html file that explains how to use the tools A Jar file containing the ant task: ant-salesforce.apache.com Migration Tool In addition to the Force. Click Your Name > Setup > Develop > Tools. Verify that the JDK and Ant are installed correctly by opening a command prompt. The Zip file contains the following: • • • A Readme. Visit http://ant.properties file: a. respectively.cls A codepkg\triggers folder that contains SampleAccountTrigger. specifying your credentials.password fields. This should lead to 75% or more of your code being covered by unit tests. as well as bulk and single record.xml file. To remove the test class and trigger added as part of the execution of ant deployCode. using the sample class and Account trigger provided with the Force. <target name="undeployCode"> <sf:deploy username="${sf. append a security token to the password.com Migration Tool from an untrusted network. Instead.serverurl}" deployroot="codepkg"> <runTest>SampleDeployClass</runTest> </sf:deploy> </target> For more information on deploy. All classes and triggers must compile successfully. enter the following in the command window: ant undeployCode. see Understanding deploy on page 597.username}" password="${sf. b. running the tests for just 1 class --> <sf:deploy username="${sf. • At least 75% of your Apex code must be covered by unit tests.salesforce.serverurl}" deployroot="removecodepkg"/> </target> Understanding deploy The deploy call completes successfully only if all of the following must be true. This runs the deploy API call. If you are deploying to a sandbox organization. ◊ ◊ ◊ ◊ When deploying to a production organization.Deploying Apex Understanding deploy • If you are using the Force.username}" password="${sf.Upload the contents of the "codepkg" package. Open a command window in the sample directory. and all of those tests must complete successfully. Test methods and test classes are not counted as part of Apex code coverage. see “Resetting Your Security Token” in the Salesforce online help. The ant deployCode calls the Ant target named deploy in the build. 12.Shows deploying code & running tests for package 'codepkg' --> <target name="deployCode"> <!-. • • Every trigger must have some test coverage.serverurl field to https://test. your focus shouldn't be on the percentage of code that is covered. ant undeployCode calls the Ant target named undeployCode in the build. Calls to System. Enter ant deployCode. While only 75% of your Apex code must be covered by tests. you should make sure that every use case of your application is covered. 597 . You cannot run more than one deploy Metadata API call at the same time. Note the following.com Migration Tool.xml file. every unit test in your organization namespace is executed. 10. To learn more about security tokens.password}" serverurl="${sf.com.debug are not counted as part of Apex code coverage. change the sf. including positive and negative cases.password}" serverurl= "${sf. 11. <!-. xml For example.xml. and other objects to be deployed. You can modify the build.trigger ◊ triggername. The best way to create the necessary file structure is to retrieve it from your organization or sandbox.xml sample to include your organization's classes and triggers.trigger-meta. false otherwise. triggers. the default is www. The root directory contains an XML file package. The -meta.xml file contains the API version and the status (active/inactive) of the trigger. named as follows: ◊ triggername. If you do not specify a value. The -meta. If you do not specify a value.com. password The password associated for logging into the Salesforce production organization.xml For example. You must have two files for each trigger. that you want to deploy. You must have two files for each class. triggers.cls ◊ classname. the default is false. Every unit test in your organization namespace is executed.cls-meta. See Understanding retrieveCode on page 599 for more information. • • • checkOnly Specifies whether the classes and triggers are deployed to the target environment or not.xml that lists all the classes. serverURL The URL for the Salesforce server you are logging into. 598 .com Migration Tool provides the task deploy which can be incorporated into your deployment scripts.xml that lists all the classes. runTests The name of the class that contains the unit tests that you want to run.cls and MyClass. MyClass. and other objects to be deleted from your organization.xml. named as follows: ◊ classname. MyTrigger.salesforce.trigger and MyTrigger. Apex trigger files must be in a subdirectory named triggers. deployRoot The local directory that contains the Apex classes and triggers.cls-meta.xml file contains the API version and the status (active/inactive) of the class. The root directory optionally contains an XML file destructiveChanges. • Apex class files must be in a subdirectory named classes. Note: This parameter is ignored when deploying to a Salesforce production organization.trigger-meta. This property takes a Boolean value: true if you do not want to save the classes and triggers to the organization. The properties of the deploy task are as follows: username The username for logging into the Salesforce production organization.Deploying Apex Understanding deploy The Force. as well as any other metadata. apiversion Which version of the Metadata API at which the files should be retrieved. for this example. In this example. use the retrieve ant task as illustrated by the sample build target ant retrieveCode: <target name="retrieveCode"> <!-. serverURL The URL for the Salesforce server you are logging into.salesforce. However.xml lists the metadata components to be retrieved. During the normal deploy cycle. You should not specify a value for runTests if you specify true for runAllTests. overwriting everything already in the directory.com. you would run retrieveCode prior to deploy.password}" serverurl="${sf. To retrieve classes and triggers from an existing organization. You should either specify this parameter or packageNames. false if you do not.username}" password="${sf. 599 .xml into the codepkg directory --> <sf:retrieve username="${sf. password The password associated for logging into the Salesforce production organization. Every unit test in your organization namespace is executed. to ensure that there is something to retrieve.xml"/> </target> The file codepkg/package. unpackaged The name of file that contains the list of files that should be retrieved. packageNames The name of the package or packages that should be retrieved. Note: This parameter is ignored when deploying to a Salesforce production organization. The retrieved files are put into the directory codepkg. The properties of the retrieve task are as follows: username The username for logging into the Salesforce production organization. it retrieves two classes and one trigger.Deploying Apex Understanding retrieveCode runAllTests This property takes a Boolean value: true if you want run all tests in your organization.Retrieve the contents listed in the file codepkg/package. retrieveTarget The directory into which the files should be copied. the default is www.serverurl}" retrieveTarget="codepkg" unpackaged="codepkg/package. If you do not specify a value. Understanding retrieveCode Use the retrieveCode call to retrieve classes and triggers from your sandbox or production organization. deploy is used first. in order to obtain the correct directory structure for your new classes and triggers. Optional.com Migration Tool. If you are using a security token. all the tests in that namespace are executed. This call takes the following properties: class The name of the class that contains the unit tests. The name of a file manifest that specifies the components to retrieve. Optional. paste the 25-digit token value to the end of your password. false otherwise. For a sandbox. defaults to false. use test. The Salesforce username for login. The salesforce server URL (if blank. The number of milliseconds to wait between each poll of salesforce. Required. The username you use to log into the organization associated with this project. this is only enabled for System Administrator users. A list of file names to retrieve. This property takes a Boolean value: true if you want to run all tests. The number of times to poll salesforce. you can also use the runTests() API call. Optional. The root of the directory structure to retrieve the metadata files into.com to retrieve the results. You can specify this property more than once. 600 . alltests Specifies whether to run all tests.com. Optional. A list of the names of the packages to retrieve. serverurl pollWaitMillis maxPoll retrieveTarget unpackaged singlePackage packageNames specificFiles Understanding runTests() In addition to using deploy() with the Force. defaults to 10. Typically.salesforce.Deploying Apex Understanding runTests() Table 6: build. The username associated with this connection must have the “Modify All Data” permission.com). Optional. defaults to 5000. defaults to www. If you specify a namespace. Specifies whether the contents being retrieved are a single package. namespace The namespace that you would like to test.xml retrieve target field settings Field username password Description Required. Required. Optional. Optional.salesforce.com for the results of the report. as well as the values for any fields that need to be set.com Migration Tool to deploy Apex. or the Force. change sets. 601 . you can use the following SOAP API calls to deploy your Apex to a development or sandbox organization: • • • compileAndTest() compileClasses() compileTriggers() All these calls take Apex code that contains the class or trigger.com IDE.Deploying Apex Using SOAP API to Deploy Apex Using SOAP API to Deploy Apex If you do not want to use the Force. or order.developerforce. Note: The Hello World and the shipping invoice samples require custom fields and objects. The following assumptions are made: • • • • Item A cannot be in both orders shipping_invoice1 and shipping_invoice2. The shipping rate is 75 cents per pound. For more information. and then adds items to the invoice. The total amount for the order. 602 .com/index. You can either create these on your own. Data and Code Models This sample application uses two new objects: Item and Shipping_invoice. Many of the syntactic and semantic features of Apex. • • Shipping Invoice Example Walk-Through on page 602 Shipping Invoice Example Code on page 605 Shipping Invoice Example Walk-Through The sample application in this section includes traditional Salesforce functionality blended with Apex. Scenario In this sample application.com AppExchange. including shipping cost. is automatically calculated and updated based on the items added or deleted from the invoice. see wiki. the user creates a new shipping invoice. This is a more complex example than the Hello World example.php/Documentation. along with common idioms. fields and Apex code as a managed packaged from Force. are illustrated in this application. Once an order is over $100.APPENDICES Appendix A Shipping Invoice Example This appendix provides an example of an Apex application. Two customers cannot obtain the same (physical) product.25%. or download the objects. the shipping discount is applied (shipping becomes free). The tax rate is 9. including tax and shipping The amount charged for shipping (assumes $0. calculating if there is a shipping discount Shipping_invoice ShippingDiscount The following is the general flow of user actions and when triggers run: 603 . after delete after update Description Updates the shipping invoice. used to calculate shipping costs The order this item is associated with The fields in the Shipping_invoice custom object include: Name Name Subtotal GrandTotal Shipping ShippingDiscount Tax TotalWeight Type String Currency Currency Currency Currency Currency Number Description The name of the shipping invoice/order The subtotal The total amount. after update. calculates the totals and shipping Updates the shipping invoice. This application has the following triggers: Object Item Trigger Name Calculate When Runs after insert.25%) The total weight of all items All of the Apex for this application is contained in triggers.Appendix A: Shipping Invoice Example Shipping Invoice Example Walk-Through The fields in the Item custom object include: Name Name Price Quantity Weight Shipping_invoice Type String Currency Number Number Master-Detail (shipping_invoice) Description The name of the item The price of the item The number of items in the order The weight of the item.75 per pound) Only applied once when subtotal amount reaches $100 The amount of tax (assumes 9. Part of the Calculate trigger updates the shipping invoice. 4. 5. 2. In Shipping Invoice Example Code both of the triggers and the test class are listed. Calculate trigger runs. one piece of the shipping invoice application is a class used for testing the triggers. Testing the Shipping Invoice Application Before an application can be included as part of a package. ShippingDiscount trigger runs. The test class verifies the following actions are completed successfully: • • • • • Inserting items Updating items Deleting items Applying shipping discount Negative test for bad input 604 . 75% of the code must be covered by unit tests. User can then add. Therefore. and clicks Save. User clicks New Item. 3. names the shipping invoice and clicks Save. fills out information. delete or change items in the invoice.Appendix A: Shipping Invoice Example Shipping Invoice Example Walk-Through Figure 13: Flow of user action and triggers for the shopping cart application 1. The comments in the code explain the functionality. User clicks Orders > New. } // Accessing all shipping invoices associated with the items in the trigger List<Shipping_Invoice__C> AllShippingInvoices = [SELECT Id. // This will make it easier to look up a shipping invoice // because you must iterate a list. for(item__c i :itemList){ // Assert numbers are not negative.isUpdate){ itemList = Trigger. 'Weight must be non-negative').isInsert || trigger.quantity__c > 0. } // Access all the information we need in a single query // rather than querying when we need it. } else if(trigger.assert(i. 'Quantity must be positive'). Map<ID. GrandTotal__c FROM Shipping_Invoice__C WHERE Id IN :AllItems]. Shipping_Invoice__C>().Shipping_Invoice__C). it won't get added to a set AllItems.isDelete) { // Note -. Shipping_Invoice__C>(). // Take the list we just populated and put it into a Map. for(Shipping_Invoice__C sc : AllShippingInvoices) { 605 .price__c >= 0. 'Price must be non-negative').there is no trigger.weight__c >= 0.assert(i. but you can use lookup for a map. Shipping_Invoice__C> SIMap = new Map<ID. if(trigger.old. System. subtract = 1.new in delete itemList = trigger. // Set this integer to -1 if we are deleting Integer subtract .assert(i. subtract = -1. after delete) { // Use a map because it doesn't allow duplicate values Map<ID.new. ShippingDiscount__c. // None of the fields would make sense with a negative value System. SubTotal__c. // Populate the list of items based on trigger type List<Item__c> itemList. // This is a best practice for bulkifying requests set<Id> AllItems = new set<id>(). // If there is a duplicate Id. Shipping_Invoice__C> updateMap = new Map<ID.Appendix A: Shipping Invoice Example Shipping Invoice Example Code Shipping Invoice Example Code The following triggers and test class make up the shipping invoice example application: • • • Calculate trigger ShippingDiscount trigger Test class Calculate Trigger trigger calculate on Item__c (after insert. after update. System.add(i. TotalWeight__c. Tax__c. price__c * itemToProcess. sc). // Decrement the previous value from the subtotal and weight. myOrder.isUpdate) { // Treat updates like a removal of the old item and addition of the // revised item rather than figuring out the differences of each field // and acting accordingly. myOrder.id. x++) { Shipping_Invoice__C myOrder. myOrder).price__c * trigger. x < Trigger.SubTotal__c -= (trigger.Shipping__c. // Leveraging Custom Settings for tax rates is a best practice.new[x].tax__c + myOrder.old[x].Subtotal__c * . myOrder.TotalWeight__c += (itemToProcess.old[x].new[x]. // Leveraging Custom Settings for the shipping rate is a best practice.quantity__c).quantity__c). } } else { for(Item__c itemToProcess : itemList) { Shipping_Invoice__C myOrder.SubTotal__c += (itemToProcess.Tax__c = myOrder. } for(Shipping_Invoice__C myOrder : AllShippingInvoices) 606 . myOrder.Appendix A: Shipping Invoice Example Shipping Invoice Example Code SIMap.old[x]. myOrder.put(sc. this is a simple example. // Generally. // Generally.quantity__c).old[x].weight__c * trigger. // Set shipping rate to 75 cents per pound. myOrder.ShippingDiscount__c = 0.get(itemToProcess.old for(Integer x = 0.id.Shipping_Invoice__C).TotalWeight__c += (trigger.put(myOrder.quantity__c * subtract).Shipping__c = (myOrder. // Look up the correct shipping invoice from the ones we got earlier myOrder = SIMap.25% Please note.Shipping_Invoice__C). myOrder = SIMap.totalWeight__c * .new and trigger. } for(Shipping_Invoice__C myOrder : AllShippingInvoices) { // Set tax rate to 9. // Note updates have both trigger.get(trigger.weight__c * trigger.weight__c * itemToProcess. myOrder.price__c * trigger. myOrder. // See Custom Settings in the Apex Developer's guide // for more information.TotalWeight__c -= (trigger. // Reset the shipping discount myOrder.old.75).new[x]. you would never hard code values.quantity__c * subtract).GrandTotal__c = myOrder. updateMap. } // Process the list of items if(Trigger. // Increment the new subtotal and weight. myOrder.size(). // See Custom Settings in the Apex Developer's guide // for more information.0925.SubTotal__c += (trigger.new[x].quantity__c).old[x]. you would never hard code values.SubTotal__c + myOrder. update updateMap. you would never hard code values. // Leveraging Custom Settings for tax rates is a best practice. } } } Shipping Invoice Test @IsTest private class TestShippingInvoice{ // Test for inserting three items at once public static testmethod void testBulkItemInsert(){ // Create the shipping invoice. this is a simple example.75).subtotal__c >= 100. } ShippingDiscount Trigger trigger ShippingDiscount on Shipping_Invoice__C (before update) { // Free shipping on all orders greater than $100 for(Shipping_Invoice__C myShippingInvoice : Trigger.00) && (myShippingInvoice.Appendix A: Shipping Invoice Example Shipping Invoice Example Code { // Set tax rate to 9.Shipping__c. // Set shipping rate to 75 cents per pound.Tax__c = myOrder.25% Please note. } } // Only use one DML update at the end. // Reset shipping discount myOrder. // Generally. grandtotal__c = 0. tax__c = 0).ShippingDiscount__c = 0. // Insert the order and populate with items insert Order1. // See Custom Settings in the Apex Developer's guide // for more information.ShippingDiscount__c == 0)) { myShippingInvoice. myOrder. totalweight__c = 0.0925.SubTotal__c + myOrder. myOrder.tax__c + myOrder. Shipping__c = 0.GrandTotal__c += myShippingInvoice.Shipping__c = (myOrder.Subtotal__c * . // See Custom Settings in the Apex Developer's guide // for more information. 607 .ShippingDiscount__c. myShippingInvoice.put(myOrder. ShippingDiscount__c = 0.values().GrandTotal__c = myOrder. you would never hard code values. myOrder). It's a best practice to either use defaults // or to explicitly set all values to zero so as to avoid having // extraneous data in your test.Shipping__c * -1. // Generally. // This minimizes the number of DML requests generated from this trigger.new) { if((myShippingInvoice. myOrder.totalWeight__c * .ShippingDiscount__c = myShippingInvoice.id. updateMap. Shipping_Invoice__C order1 = new Shipping_Invoice__C(subtotal__c = 0. // Leveraging Custom Settings for the shipping rate is a best practice. grandtotal__c. Item__c item3 = new Item__C(Price__c = 40. Shipping_Invoice__C = order1. then do assertions order1 = [SELECT id. totalweight__c. list1.totalweight__c).assert(order1. Item__c item1 = new Item__C(Price__c = 10.4375. 'Order tax was not $6.id]. Item__c item1 = new Item__C(Price__c = 1. 'Order shipping discount was not $0 but was ' + order1. tax__c. totalweight__c = 0. Item__c item3 = new Item__C(Price__c = 4. totalweight__c.id). weight__c = 3. // Retrieve the order.assert(order1.add(item3).assert(order1. list1[1]. Shipping_Invoice__C = order1.assert(order1. quantity__c = 1.assert(order1.shippingdiscount__c == 0. System.tax__c). weight__c = 2.subtotal__c).add(item2).shipping__c).add(item2). list1. Shipping__c = 0. 'Order weight was not 6 but was ' + order1. quantity__c = 1. 'Order subtotal was not $75.4375 but was ' + order1. but was ' + order1. weight__c = 1. weight__c = 1. insert Order1. list1. weight__c = 2. Item__c item2 = new Item__C(Price__c = 2. update list1. quantity__c = 1. but was '+ order1. quantity__c = 1. grandtotal__c. } // Test for updating three items at once public static testmethod void testBulkItemUpdate(){ // Create the shipping invoice.id). System. quantity__c = 1.9375. list1[2]. shipping__c. list1.9375.00. shippingdiscount__c 608 . but was ' + order1. list1. weight__c = 3.50. insert list1. list1. shipping__c. subtotal__c. ShippingDiscount__c = 0. grandtotal__c = 0. List<Item__c> list1 = new List<Item__c>().tax__c == 6. System.price__c = 40. // Insert the order and populate with items.grandtotal__c == 86. Shipping_Invoice__C order1 = new Shipping_Invoice__C(subtotal__c = 0.add(item3).id). insert list1.id).shipping__c == 4. Shipping_Invoice__C = order1. Item__c item2 = new Item__C(Price__c = 25. System. 'Order grand total was not $86. // Access the order and assert items updated order1 = [SELECT id.50.subtotal__c == 75. tax__c = 0). quantity__c = 1. // Update the prices on the 3 items list1[0]. 'Order shipping was not $4.shippingdiscount__c). tax__c. Shipping_Invoice__C = order1. System.id). Shipping_Invoice__C = order1.totalweight__c == 6. System. subtotal__c.price__c = 10.Appendix A: Shipping Invoice Example Shipping Invoice Example Code List<Item__c> list1 = new List<Item__c>().id).add(item1). It's a best practice to either use defaults // or to explicitly set all values to zero so as to avoid having // extraneous data in your test.assert(order1.grandtotal__c).add(item1).price__c = 25. shippingdiscount__c FROM Shipping_Invoice__C WHERE id = :order1. Shipping_Invoice__C = order1. quantity__c = 1. list1.add(itemA). quantity__c = 1. Shipping_Invoice__C = order1. weight__c = 3. list2. quantity__c = 1.Id].add(itemD).id).Appendix A: Shipping Invoice Example Shipping Invoice Example Code FROM Shipping_Invoice__C WHERE Id = :order1.id). Shipping_Invoice__C = order1. Item__c itemD = new Item__C(Price__c = 1. but was ' + order1. weight__c = 3.add(itemC).grandtotal__c). System.add(item2). Shipping__c = 0.add(itemC). System. Item__c item3 = new Item__C(Price__c = 40. Shipping_Invoice__C = order1.grandtotal__c == 86. 'Order tax was not $6.assert(order1.id). ShippingDiscount__c = 0. // The following deletes four of them.shipping__c == 4.add(itemB). // Retrieve the order and verify the deletion 609 . Item__c itemC = new Item__C(Price__c = 1.add(item3).shippingdiscount__c). tax__c = 0). list2. list1.assert(order1. but was '+ order1. // Seven items are now in the shipping invoice.assert(order1. list1. weight__c = 2.totalweight__c). list1.subtotal__c). list1.tax__c). quantity__c = 1.assert(order1. delete list2. list1. // Insert the order and populate with items insert Order1.id).4375. weight__c = 3. totalweight__c = 0.4375 but was ' + order1. List<Item__c> list1 = new List<Item__c>(). Shipping_Invoice__C order1 = new Shipping_Invoice__C(subtotal__c = 0. insert list1. list1. List<Item__c> list2 = new List<Item__c>().add(itemB). weight__c = 3. quantity__c = 1. System. Shipping_Invoice__C = order1. Shipping_Invoice__C = order1. System.totalweight__c == 6.id). weight__c = 3. Item__c item2 = new Item__C(Price__c = 25.shipping__c). 'Order subtotal was not $75.id). Item__c itemA = new Item__C(Price__c = 1.id). Shipping_Invoice__C = order1.add(itemA). quantity__c = 1. list2.shippingdiscount__c == 0.9375.add(itemD). grandtotal__c = 0.50. Item__c itemB = new Item__C(Price__c = 1.assert(order1. but was ' + order1. quantity__c = 1. 'Order weight was not 6 but was ' + order1. It's a best practice to either use defaults // or to explicitly set all values to zero so as to avoid having // extraneous data in your test. 'Order shipping was not $4. weight__c = 1. 'Order grand total was not $86.subtotal__c == 75. Item__c item1 = new Item__C(Price__c = 10.9375. } // Test for deleting items public static testmethod void testBulkItemDelete(){ // Create the shipping invoice. 'Order shipping discount was not $0 but was ' + order1. System.50.tax__c == 6.assert(order1.add(item1). System.00. list2. Shipping_Invoice__C = order1. assert(order1.9375. 'Order subtotal was not $75.grandtotal__c == 86. quantity__c = 1. subtotal__c. quantity__c = 1. 'Order tax was not $6.9375.add(item1).shipping__c == 4. shippingdiscount__c FROM Shipping_Invoice__C WHERE Id = :order1. weight__c = 1.totalweight__c).00.4375 but was ' + order1.assert(order1.assert(order1.00. System.assert(order1.totalweight__c).assert(order1. System. but was '+ order1.shippingdiscount__c). tax__c = 0). Item__c item2 = new Item__C(Price__c = 25. list1.4375 but was ' + order1.id). Shipping_Invoice__C order1 = new Shipping_Invoice__C(subtotal__c = 0.totalweight__c == 6.add(item3). grandtotal__c.tax__c).grandtotal__c == 86.subtotal__c == 75.subtotal__c == 75.assert(order1. shipping__c.shipping__c == 4. tax__c.9375. grandtotal__c. shipping__c. System. Shipping_Invoice__C = order1. Shipping__c = 0.50.9375.Id]. It's a best practice to either use defaults // or to explicitly set all values to zero so as to avoid having // extraneous data in your test. 'Order weight was not 6 but was ' + order1.shipping__c). 'Order grand total was not $86.assert(order1. insert list1. Shipping_Invoice__C = order1. list1. totalweight__c = 0. 'Order grand total was not $86.50.id).assert(order1.grandtotal__c). but was ' + order1. System. System. 'Order subtotal was not $75. System. but was ' + order1.grandtotal__c). 'Order shipping discount was not $0 but was ' + order1.50. ShippingDiscount__c = 0. Item__c item1 = new Item__C(Price__c = 10.id). 'Order shipping was not $4. but was '+ order1.assert(order1. subtotal__c.assert(order1.shippingdiscount__c == 0. // Add items to increase subtotal 610 . insert Order1.Appendix A: Shipping Invoice Example Shipping Invoice Example Code order1 = [SELECT id. // Insert the order and populate with items. // Free shipping not available on $75 orders System. 'Order tax was not $6. System.tax__c == 6. Item__c item3 = new Item__C(Price__c = 40.50.subtotal__c). 'Order shipping was not $4. grandtotal__c = 0.subtotal__c).assert(order1. quantity__c = 1.4375. // Retrieve the order and verify free shipping not applicable order1 = [SELECT id. shippingdiscount__c FROM Shipping_Invoice__C WHERE Id = :order1. System.totalweight__c == 6. but was ' + order1. weight__c = 2. System. list1. but was ' + order1. System.shipping__c). Shipping_Invoice__C = order1. List<Item__c> list1 = new List<Item__c>().assert(order1. weight__c = 3. 'Order weight was not 6 but was ' + order1.add(item2). totalweight__c.shippingdiscount__c). } // Testing free shipping public static testmethod void testFreeShipping(){ // Create the shipping invoice. tax__c.4375. totalweight__c. System.shippingdiscount__c == 0. 'Order shipping discount was not $0 but was ' + order1.tax__c).tax__c == 6.Id]. 4375 but was ' + order1.50.25.contains('Weight must be non-negative'). Shipping_Invoice__C = order1. tax__c. } catch(Exception e) { system. Shipping_Invoice__C order1 = new Shipping_Invoice__C(subtotal__c = 0. System. totalweight__c = 0.tax__c == 9. insert item1.totalweight__c == 26. try{ insert item1. } 611 . but was ' + order1.subtotal__c). shippingdiscount__c FROM Shipping_Invoice__C WHERE Id = :order1. 'Order weight was not 26 but was ' + order1.id). tax__c = 0). System. but was '+ order1.id). System. grandtotal__c = 0.id). 'Order shipping was not $19. 'Order tax was not $9.50.tax__c).shipping__c == 19.00.grandtotal__c == 109. Item__c item2 = new Item__C(Price__c = 25.Appendix A: Shipping Invoice Example Shipping Invoice Example Code item1 = new Item__C(Price__c = 25. Shipping_Invoice__C = order1. subtotal__c.assert(order1.assert(order1. It's a best practice to either use defaults // or to explicitly set all values to zero so as to avoid having // extraneous data in your test. Item__c item3 = new Item__C(Price__c = 40. shipping__c.assert(order1. quantity__c = 1. weight__c = 3. weight__c = 1.subtotal__c == 100. weight__c = -2. 'Weight was negative but was not caught'). System. 'Price was negative but was not caught'). weight__c = 3.25. 'Order grand total was not $86. } catch(Exception e) { system. // Insert the order and populate with items.totalweight__c). } // Negative testing for inserting bad input public static testmethod void testNegativeTests(){ // Create the shipping invoice. quantity__c = 1.Id].shippingdiscount__c == -19. weight__c = 20.25. quantity__c = 0.shippingdiscount__c). grandtotal__c.assert(order1. // Retrieve the order and verify free shipping is applicable order1 = [SELECT id.getMessage(). insert Order1.contains('Price must be non-negative').assert(e. } try{ insert item2. Item__c item4 = new Item__C(Price__c = 40. totalweight__c. ShippingDiscount__c = 0. so free shipping should be enabled System. Shipping_Invoice__C = order1. 'Order shipping discount was not -$19. Item__c item1 = new Item__C(Price__c = -10. // Order total is now at $100. Shipping__c = 0.50.assert(order1.assert(order1.id). but was ' + order1.id). Shipping_Invoice__C = order1. System.50 but was ' + order1. quantity__c = 1.assert(e.shipping__c).grandtotal__c). 'Order subtotal was not $100. Shipping_Invoice__C = order1.getMessage(). quantity__c = -1. contains('Quantity must be positive'). } try{ insert item4. 'Quantity was negative but was not caught'). 'Quantity was zero but was not caught'). } catch(Exception e) { system.Appendix A: Shipping Invoice Example Shipping Invoice Example Code try{ insert item3.assert(e.getMessage(). } } } 612 .getMessage(). } catch(Exception e) { system.assert(e.contains('Quantity must be positive'). Appendix A: Shipping Invoice Example Shipping Invoice Example Code 613 . Note: Keywords marked with an asterisk (*) are reserved for future use.Appendix B Reserved Keywords The following words can only be used as keywords. Table 7: Reserved Keywords abstract activate* and any* array as asc autonomous* begin* bigdecimal* blob break bulk by byte* case* cast* catch char* class collect* commit const* continue convertcurrency decimal having* hint* if implements import* inner* insert instanceof interface into* int join* last_90_days last_month last_n_days last_week like limit list long loop* map merge new next_90_days next_month retrieve* return returning* rollback savepoint search* select set short* sort stat* super switch* synchronized* system testmethod then* this this_month* this_week throw today tolabel tomorrow transaction* trigger 614 . • • • • • • • • • • after before count excludes first includes last order sharing with 615 .Appendix B: Reserved Keywords default* delete desc do else end* enum exception exit* export* extends false final finally float* for from future global goto* group* next_n_days next_week not null nulls number* object* of* on or outer* override package parallel* pragma* private protected public true try type* undelete update upsert using virtual webservice when* where while yesterday The following are special types of keywords that aren't reserved words and can be used as identifiers. location='http://www.Appendix C Security Tips for Apex and Visualforce Development Understanding Security The powerful combination of Apex and Visualforce pages allow Force. while others are unique to Apex.com page using a script component. The Web application includes malicious scripting in a response to a user of the Web application.cgi?'%2Bdocument. developers must be cognizant of potential security-related pitfalls. However.com platform.com platform itself. <script>var foo = '{!$CurrentPage. see the Force.com Security Resources page on Developer Force at http://wiki. Most applications that display dynamic Web pages without properly validating the data are likely to be vulnerable. Many of the coding mistakes a developer can make on the Force. However. assume the following script is included in a Force. Salesforce.parameters. The attacker has used the Web application as an intermediary in the attack.script>var foo = '{!$CurrentPage. Cross Site Scripting (XSS) Cross-site scripting (XSS) attacks cover a broad range of attacks where malicious HTML or client-side scripting is provided to a Web application.developerforce. news.com platform are similar to general Web application security vulnerabilities.parameters. an on* event. The attacker can then enter the following value for userparam: 1'. Attacks against the website are especially easy if input from one user is intended to be displayed to another user. Some obvious possibilities include bulletin board or user comment-style websites. or email archives. taking advantage of the victim's trust for the Web application. it is important that developers learn and understand the security flaws described here. For additional information.var%20foo='2 616 .com has incorporated several security defenses into the Force.com/cgi-bin/cookie. careless developers can still bypass the built-in defenses in many cases and expose their applications and customers to security risks.document.com developers to provide custom functionality and business logic to Salesforce or create a completely new stand-alone product running inside the Force. or a Visualforce page.userparam}'.cookie. The user then unknowingly becomes the victim of the attack. For example.</script> This script block inserts the value of the user-supplied userparam onto the page.attacker.com/page/Security. as with any programming language.userparam}'. To certify an application for AppExchange. the following code is normally vulnerable to an XSS attack because it takes user-supplied input and outputs it directly back to the user. document. which start with <apex>. </script> 617 .cgi script.userInput} </apex:outputText> Disabling Escape on Visualforce Tags By default.com as the query string in the request to the cookie.google. It is possible to disable this behavior by setting the optional attribute escape="false". All characters that appear to be HTML tags are converted to their literal form. so that a literal < displays on the user's screen.owasp.com/articles/xss-faq. see the following articles: • • • • http://www. salesforce.com/search?q=cross-site+scripting Within the Force. the < character is converted to <.userInput}" /> Programming Items Not Protected from XSS The following items do not have built-in XSS protections.write(foo). Web application users not only see the attacker's input. For more information on this attack in general. For example.php/Cross_Site_Scripting http://www.owasp. Existing Protection All standard Visualforce components. the threats of XSS flaws have been largely mitigated.cgisecurity.php/Testing_for_Cross_site_scripting http://www. For example. However. With this ability. For example. the attacker has the victim's session cookie and can connect to the Web application as if they were the victim. such as opening and closing windows. the attacker can perform a wide variety of attacks against the victim.attacker.parameters. all of the cookies for the current page are sent to www. <script> var foo = location. have anti-XSS filters in place. the following output is vulnerable to XSS attacks: <apex:outputText escape="false" value="{!$CurrentPage. allowing an attacker full access to the victim's session. It does not makes sense to include anti-XSS filters on commands that are intentionally added to a page.com platform there are several anti-XSS defenses in place.org/index. Custom JavaScript If you write your own JavaScript. such as stealing data or session cookies.parameters.org/index. but the <apex:outputText> tag is XSS-safe. This is because these items were intended to allow the developer to customize the page by inserting script commands. These range from simple actions. For example. For the developer using standard classes and output methods. so take extra care when using these tags and objects.Appendix C: Security Tips for Apex and Visualforce Development Cross Site Scripting (XSS) In this case. to more malicious attacks. the creative developer can still find ways to intentionally or accidentally bypass the default controls.com has implemented filters that screen out harmful characters in most output methods. but their browser can execute the attacker's script in a trusted context. For example. The following sections show where protection does and does not exist.shtml http://www.com platform has no way to protect you. the following code is vulnerable to XSS if used in JavaScript. <apex:outputText> {!$CurrentPage. the Force. At this point.search. The attacker can post a malicious script using a Website or email. nearly all Visualforce tags escape the XSS-vulnerable characters. be very careful to validate that the content is safe and does not include user-supplied data. such as a backslash (\).. HTMLENCODE The HTMLENCODE function encodes text strings and merge field values for use in HTML by replacing characters that are reserved in HTML.parameters. 618 . system environment. such as the greater-than sign (>). JSENCODE The JSENCODE function encodes text strings and merge field values for use in JavaScript by inserting escape characters. A common vulnerability is created by rerendering user input on a page. In these cases. Since expressions are rendered on the server. It is important to be aware that the output that is generated by expressions is not escaped during rendering. <apex:page standardController="Account"> <apex:form> <apex:commandButton rerender="outputIt" value="Update It"/> <apex:inputText value="{!myTextField}"/> </apex:form> <apex:outputPanel id="outputIt"> Value of myTextField is <apex:outputText value=" {!myTextField}" escape="false"/> </apex:outputPanel> </apex:page> The unescaped {!myTextField} results in a cross-site scripting vulnerability. This can lead to potentially dangerous situations if the formula expression references non-system data (that is potentially hostile or editable data) and the expression itself is not wrapped in a function to escape the output during rendering. they can potentially direct the victim to include any JavaScript file from any other website. <apex:includeScript value="{!$CurrentPage. if the user enters : <script>alert('xss') and clicks Update It. such as >. or when including formulas outside of a Visualforce component. For example. it is not possible to escape rendered data on the client using JavaScript or other client-side technology. with HTML entity equivalents. a user's environment. There are several functions that you can use for escaping potentially insecure strings. For example. an alert dialog is displayed. but more malicious uses could be designed. before unsafe JavaScript characters. the following snippet is extremely vulnerable because it includes user-supplied input as the value of the script text. For example. the JavaScript is executed. such as the apostrophe ('). This is especially important when using formula expressions. If an attacker can supply arbitrary data to this parameter (as in the example below).userInput}" /> Unescaped Output and Formulas in Visualforce Pages When using components that have set the escape attribute to false. Formula expressions can be function calls or include information about platform objects. The value provided by the tag is a URL to the JavaScript to include.Appendix C: Security Tips for Apex and Visualforce Development Unescaped Output and Formulas in Visualforce Pages <apex:includeScript> The <apex:includeScript> Visualforce component allows you to include a custom script on the page. In this case. output is unfiltered and must be validated for security. and the request environment. and the alert is displayed. For example.</script> The JavaScript executes. to prevent the JavaScript being executed.attacker.com. with the code that represent those characters as defined in RFC 3986.</script> requires that the double quote character be escaped with its URL encoded equivalent of %22 instead of the HTML escaped ". In this case.parameters.retURL}". both the characters needing escaping as well as their escaped counterparts may vary.//".html?retURL=%22foo%22%3Balert('xss')%3B%2F%2F results in: <script>var ret = "foo". the request: http://example.com/demo/redirect. change the <apex:outputText> to the following: <apex:outputText value=" {!HTMLENCODE(myTextField)}" escape="false"/> If a user enters <script>alert('xss') and clicks Update It. since it is going to be used in a link. Additionally. they undermine the organization's user roles and reduce the integrity of auditing records. many organizations contain data which has been imported from external sources and may not have been screened for malicious content.script>var ret = "{!$CurrentPage.Appendix C: Security Tips for Apex and Visualforce Development Cross-Site Request Forgery (CSRF) JSINHTMLENCODE The JSINHTMLENCODE function encodes text strings and merge field values for use in JavaScript within HTML tags by inserting escape characters before unsafe JavaScript characters and replacing characters that are reserved in HTML with HTML entity equivalents. Cross-Site Request Forgery (CSRF) Cross-Site Request Forgery (CSRF) flaws are less of a programming mistake as they are a lack of a defense.parameters. Depending on the placement of the tag and usage of the data.alert('xss'). URLENCODE The URLENCODE function encodes text strings and merge field values for use in URLs by replacing characters that are illegal in URLs. The easiest way to describe CSRF is to provide a very simple example.retURL)}".retURL}". An attacker has a Web page at www. Otherwise.parameters. For instance. such as blank spaces. Although the data is taken directly from the user's organization. it must still be escaped before use to prevent users from executing code in the context of other users (potentially those with higher privilege levels). the JavaScript is not be executed. This could be 619 . exclamation points are replaced with %21.</script> Formula tags can also be used to include platform object data. To use HTMLENCODE to secure the previous example. While these types of attacks must be performed by users within the same organization. use the JSENCODE function. Instead. For example <script>var ret = "{!JSENCODE($CurrentPage. Uniform Resource Identifier (URI): Generic Syntax. this statement: <script>var ret = "{!$CurrentPage. the string is encoded and the page displays Value of myTextField is <script>alert('xss'). cgisecurity.yourwebpage. The anti-CSRF token is never read or validated. In summary SQL/SOQL injection involves taking user-supplied input and using those values in a dynamic SOQL query.owasp. For example. suppose you have a custom controller where you take the object ID as an input parameter..com has implemented an anti-CSRF token to prevent this attack.Appendix C: Security Tips for Apex and Visualforce Development SOQL Injection any Web page.getParameters(). Therefore. see the following articles: • • • http://www. If the user is still logged into your Web page when they visit the attacker's Web page.currentPage().org/articles/cross-site-request-forgeries Within the Force. the attacker's page contains a URL that performs an action on your website. There are no built-in defenses for situations like this and developers should be cautious about writing pages that take action based upon a user-supplied parameter like the id variable in the preceding example. SOQL... delete obj." height=1 width=1 /> In other words. the previous flaw is known as SQL injection. Other suggestions include shortening the idle session timeout for the organization and educating users to log out of their active session and not use their browser to visit other sites while authenticated. This feature protects you when using all of the standard controllers and methods. This attack succeeds because the user is still authenticated to your Web page. return . Upon the next page load. the developer has unknowingly bypassed the anti-CSRF controls by developing their own action method. the risks are much lower for SOQL injection than for SQL injection.org/index. salesforce. <apex:page controller="myClass" action="{!init}"</apex:page> public class myClass { public void init() { Id id = ApexPages. Here again. Every page includes a random string of characters as a hidden form field. A possible work-around is to insert an intermediate confirmation page before taking the action.com/yourapplication/createuser?email=attacker@attacker. If 620 . An attacker Web page might have sent the user to this page using a CSRF attack and provided any value they wish for the id parameter. to make sure the user intended to call the page.shtml http://shiflett. then use that input parameter in an SOQL call. Name FROM Account WHERE id = :id]. The id parameter is read and used in the code.com platform. including one that provides valuable services or information that drives traffic to that site. but uses its own database query language. but the attacks are nearly identical to traditional SQL injection. the developer might bypass the built-in defenses without realizing the risk.. the URL is retrieved and the actions performed. Account obj = [select id. SOQL is much simpler and more limited in functionality than SQL.get('id'). the application checks the validity of this string of characters and does not execute the command unless the value matches the expected value.com&type=admin. Consider the following code snippet. For more information and traditional defenses. This is a very simple example and the attacker can get more creative by using scripts to generate the callback request or even use CSRF attacks against your AJAX methods. SOQL Injection In other programming languages. Apex does not use SQL. } } In this case. Somewhere on the attacker's page is an HTML tag that looks like this: <img src="http://www.php/Cross-Site_Request_Forgery http://www.com/articles/csrf-faq. query(qryString). The code is intended to search for contacts that have not been deleted.org/index. not just the non-deleted ones.} } public PageReference query() { String qryString = 'SELECT Id FROM Contact WHERE ' + '(IsDeleted = false and Name like \'%' + name + '%\')'. what if the user provides unexpected input.google. For more information on SQL Injection attacks see: • • • • http://www. A SOQL Injection flaw can be used to modify the intended logic of any vulnerable query.owasp.Appendix C: Security Tips for Apex and Visualforce Development SOQL Injection the input is not validated. 621 . <apex:page controller="SOQLController" > <apex:form> <apex:outputText value="Enter Name" /> <apex:inputText value="{!name}" /> <apex:commandButton value="Query" action="{!query}“ /> </apex:form> </apex:page> public class SOQLController { public String name { get { return name. The SOQL query is built dynamically and then executed with the Database.query method. the query string becomes: SELECT Id FROM Contact WHERE (IsDeleted = false AND Name LIKE '%test%') OR (Name LIKE '%') Now the results show all contacts. return null. such as: // User supplied value for name: test%') OR (Name LIKE ' In that case. the statement executes as expected: // User supplied value: name = Bob // Query string SELECT Id FROM Contact WHERE (IsDeleted = false and Name like '%Bob%') However.php/Guide_to_SQL_Injection http://www.owasp. The value can be anything provided by the user and it is never validated. } } This is a very simple example but illustrates the logic.owasp. The user provides one input value called name. queryResult = Database. If the user provides a legitimate value.php/SQL_injection http://www.org/index. it can include SOQL commands that effectively modify the SOQL statement and trick the application into performing unintended commands.php/Blind_SQL_Injection http://www.org/index.com/search?q=sql+injection SOQL Injection Vulnerability in Apex Below is a simple example of Apex and Visualforce code vulnerable to SOQL injection.} set { name = value. and delete. rather than granting full access to all records. create. The method ensures that all single quotation marks are treated as enclosing strings. consider the following Apex pseudo-code: public class customController { public void read() { Contact contact = [SELECT id FROM Contact WHERE Name = :value].com platform makes extensive use of data sharing rules. use the escapeSingleQuotes method to sanitize user-supplied input. instead of database commands. This method adds the escape character (\) to all single quotation marks in a string that is passed in from a user. These settings are enforced when using all standard controllers. return null.Appendix C: Security Tips for Apex and Visualforce Development Data Access Control SOQL Injection Defenses To prevent a SOQL injection attack. Data Access Control The Force. } } In this case. Because these rules are not enforced. all contact records are searched. avoid using dynamic SOQL queries. When using an Apex class. . even if the user currently logged in would not normally have permission to view these records. field-level security. The solution is to use the qualifying keywords with sharing when declaring the class: public with sharing class customController { . developers who use Apex must take care that they do not inadvertently expose sensitive data that would normally be hidden from users by user permissions. the built-in user permissions and field-level security restrictions are not respected during execution. For example. Each object has permissions and may have sharing settings for which users can read. } The with sharing keyword directs the platform to use the security sharing permissions of the user currently logged in. edit. Instead. This is particularly true for Visualforce pages. 622 . } } If you must use dynamic SOQL. The vulnerable example above can be re-written using static SOQL as follows: public class SOQLController { public String name { get { return name. use static queries and binding variables. or organization-wide defaults. . queryResult = [SELECT Id FROM Contact WHERE (IsDeleted = false and Name like :queryName)]. The default behavior is that an Apex class has the ability to read and update all data within the organization.} set { name = value.} } public PageReference query() { String queryName = '%' + name + '%'. Appendix C: Security Tips for Apex and Visualforce Development Data Access Control 623 . This allows an external application to invoke an Apex Web service to perform an action in Salesforce. contact your salesforce.0 For information on all other SOAP API calls.com representative.salesforce. use endpoint 27. see Considerations for Using the WebService Keyword on page 227. including those that can be used to extend or implement any existing Apex IDEs. Note: Apex class methods can be exposed as custom SOAP Web service calls. For example. Any Apex code saved using SOAP API calls uses the same version of SOAP API as the endpoint of the request. Use the webService keyword to define these methods.Appendix D SOAP API and SOAP Headers for Apex This appendix details the SOAP API calls and objects that are available by default for Apex. if you want to use SOAP API version 27.0.0 and later: • • ApexTestQueueItem ApexTestResult The following are SOAP API calls: • • • • • compileAndTest() compileClasses() compileTriggers() executeanonymous() runTests() The following SOAP headers are available in SOAP API calls for Apex: • • DebuggingHeader PackageVersionHeader Also see the Metadata API Developer's Guide for two additional calls: • • deploy() retrieve() 624 . For more information.0: https://na1-api. The following API objects are available as a Beta release in API version 23.com/services/Soap/s/27. the queue items will share the same parent job. If you insert multiple Apex test queue items in a single bulk operation.0 and later. Sort Description Read-only. ParentJobId Type reference Properties Filter. this field contains the cause of the failure.Appendix D: SOAP API and SOAP Headers for Apex ApexTestQueueItem ApexTestQueueItem Note: The API for asynchronous test runs is a Beta release. This field can't be updated. Sort Description The Apex class whose tests are to be executed. upsert() Fields Field Name ApexClassId Description Type reference Properties Create. This object is available in API version 23. If the class fails to execute. Nillable. Supported Calls create(). Filter. Represents a single Apex class in the Apex job queue. Points to the AsyncApexJob that represents the entire test run. Group. This means that four out of a total of six tests passed. describeSObjects(). For example: “(4/6)”. Nillable. Sort Description The pass rate of the test run. ExtendedStatus Type string Properties Filter. query(). update(). This means that a test run 625 . retrieve(). Group. Update Description The status of the job. Valid values are: • Queued • Processing • Aborted • Completed • Failed • Preparing Usage Insert an ApexTestQueueItem object to place its corresponding Apex class in the Apex job queue for execution. Sort. The Apex job executes the test methods in the class. Restricted picklist. If you insert multiple Apex test queue items in a single bulk operation. This means that a test run can consist of the execution of the tests of several classes if all the test queue items are inserted in the same bulk operation. Represents the result of an Apex test method execution. To abort a class that is in the Apex job queue. This object is available in API version 23.0 and later. perform an update operation on the ApexTestQueueItem object and set its Status field to Aborted. retrieve() 626 . Supported Calls describeSObjects(). Group. the queue items will share the same parent job. Status Type picklist Properties Filter. ApexTestResult Note: The API for asynchronous test runs is a Beta release. query().Appendix D: SOAP API and SOAP Headers for Apex ApexTestResult Field Name Description can consist of the execution of the tests of several classes if all the test queue items are inserted in the same bulk operation. Nillable. Sort Description The exception error message if a test failure occurs.Appendix D: SOAP API and SOAP Headers for Apex ApexTestResult Fields Field Name ApexClassId Details Type reference Properties Filter. AsyncApexJobId Type reference Properties Filter. otherwise. null. Nillable. Nillable. Nillable. Sort Description Points to the ApexLog for this test method execution if debug logging is enabled. null. Message Type string Properties Filter. Sort Description The Apex class whose test methods were executed. Sort Description Read-only. Sort 627 .ParentJobId. MethodName Type string Properties Filter. This field points to the same object as ApexTestQueueItem. Group. otherwise. ApexLogId Type reference Properties Filter. Group. Points to the AsyncApexJob that represents the entire test run. Group. Group. otherwise. Can be one of these values: • • • Pass Fail CompileFail QueueItemId Type reference Properties Filter. null. Sort Description The Apex stack trace if the test failed. Restricted picklist. Usage You can query the fields of the ApexTestResult record that corresponds to a test method executed as part of an Apex class execution. Sort Description The result of the test method execution. Nillable. TestTimestamp Type dateTime Properties Filter.Appendix D: SOAP API and SOAP Headers for Apex ApexTestResult Field Name Details Description The test method name. Group. Sort Description Points to the ApexTestQueueItem which is the class that this test method is part of. Nillable. Sort Description The start time of the test method. StackTrace Type string Properties Filter. Group. Outcome Type picklist Properties Filter. 628 . see the SOAP API Developer's Guide.new){ " + " a. String triggerBody = "trigger t1 on Account (before insert){ " + " for(Account a:Trigger. the RunTestsRequest property of the CompileAndTestRequest is ignored." + }" + // TEST // Compile only one class which meets all test requirements for checking 629 ." + " System. Syntax CompileAndTestResult[] = compileAndTest(CompileAndTestRequest request).}" + "}".id]. classBody = "public class c1{" + public static String s ='HELLO'. This call supports the DebuggingHeader and the SessionHeader. String classToTestTriggerBody = "public class TestT1{" + " public static testmethod void test1(){" + " Account a = new Account(name='TEST'). but the classes are not saved to the database. Production organizations (not a Developer Edition or Sandbox Edition) must use this call instead of compileClasses() or compileTriggers(). if an Apex test class contains six test methods.assert(s=='HELLO'). These records are in addition to the ApexTestQueueItem record that represents the Apex class." + public static testmethod void test1(){" + System. For more information about the SOAP headers in the API." + " insert(a). and all unit tests defined in the organization are run and must pass." + " }" + "}". For example. six ApexTestResult records are created. Usage Use this call to both compile and test the Apex you specify with a single call.description.contains('t1_UPDATE')).assert(a. String " " " " "}"." + " a = [select id.Appendix D: SOAP API and SOAP Headers for Apex compileAndTest() Each test method execution is represented by a single ApexTestResult record. compileAndTest() Compile and test your Apex in a single call. All specified tests must pass.description = 't1_UPDATE'. { CompileAndTestRequest request.description from Account where id=:a. CompileAndTestResult result = null. otherwise data is not saved to the database. If this call is invoked in a production organization. Sample Code—Java Note that the following example sets checkOnly to true so that this class is compiled and tested. whether or not the code successfully compiles and unit tests pass. the Apex classes and triggers submitted are not saved to your organization.isSuccess()). This is the same requirement as Force. 630 . } Arguments Name request Type CompileAndTestRequest Description A request that includes the Apex and the values for any fields that need to be set for this request. Content of the class or classes to be compiled. } catch (RemoteException e) { System. triggers Note the following about this object: • • • This object contains the RunTestsRequest property. All triggers must have code coverage.Appendix D: SOAP API and SOAP Headers for Apex CompileAndTestRequest request = new CompileAndTestRequest(). Name of the class or classes to be deleted. a request with information about the Apex to be compiled.getMessage()).println("An unexpected error occurred: " + e.setCheckOnly(true).out. Name of the trigger or triggers to be deleted.com AppExchange package testing. testing. request.setClasses(new String[]{classBody. the property is ignored and all tests are run. } assert (result.setTriggers(new String[]{triggerBody}). this property is ignored and all unit tests are run for your entire organization. string Content of the trigger or triggers to be compiled. request. no classes or triggers are saved to your organization. classes deleteClasses deleteTriggers runTestsRequest RunTestsRequest Specifies information about the Apex to be tested. or if the goal of 75% code coverage is missed. request. If a trigger has no code coverage. If the request is run in a production organization. Response CompileAndTestResult CompileAndTestRequest The compileAndTest() call contains this object. no classes or triggers are saved to your organization.compileAndTest(request). A CompileAndTestRequest object has the following properties: Name checkOnly Type boolean string string string Description If set to true. delete. If any errors occur during compile. If this request is sent in a production organization. classToTestTriggerBody}). try { result = apexBinding. The ID is unique within an organization. If true. CompileClassResult This object is returned as part of a compileAndTest() or compileClasses() call. The name of the class. The line number where an error occurred. or unit test failed. all of the classes. A CompileClassResult object has the following properties: Name bodyCrc column id Type int* int* ID* int* string* Description The CRC (cyclic redundancy check) of the class or trigger file. Information about the success or failure of the Apex unit tests. A CompileAndTestResult object has the following properties: Name classes Type CompileClassResult DeleteApexResult DeleteApexResult RunTestsResult boolean* Description Information about the success or failure of the compileAndTest() call if classes were being compiled. It contains information about whether or not the compile and run of the specified Apex was successful. If any class. the value is false. if one did. including whether it succeeded or failed. if one did. The column number where an error occurred. Information about the success or failure of the compileAndTest() call if classes were being deleted. Information about the success or failure of the compileAndTest() call if triggers were being deleted.Appendix D: SOAP API and SOAP Headers for Apex CompileAndTestResult CompileAndTestResult The compileAndTest() call returns information about the compile and unit test run of the specified Apex. and unit tests specified ran successfully. triggers. trigger. line name 631 . deleteClasses deleteTriggers runTestsResult success triggers CompileTriggerResult * Link goes to the SOAP API Developer's Guide. and details are reported in the corresponding result object: • CompileClassResult • CompileTriggerResult • DeleteApexResult • RunTestsResult Information about the success or failure of the compileAndTest() call if triggers were being compiled. if any were specified. An ID is created for each compiled class. all the specified triggers compiled and ran successfully. The description of the problem if an error occurred. the value is false. CompileTriggerResult This object is returned as part of a compileAndTest() or compileTriggers() call. the value is false.Appendix D: SOAP API and SOAP Headers for Apex CompileAndTestResult Name problem success Type string* boolean* Description The description of the problem if an error occurred. The ID is unique within an organization. An ID is created for each compiled trigger. problems are specified in other properties of this object. If true. 632 . * Link goes to the SOAP API Developer's Guide. If true. The name of the trigger. The description of the problem if an error occurred. all the specified classes or triggers were deleted successfully. If any class or trigger is not deleted. If false. if one did. The ID is unique within an organization. A CompileTriggerResult object has the following properties: Name bodyCrc column id Type int* int* ID* int* string* string* boolean* Description The CRC (cyclic redundancy check) of the trigger file. the class or classes compiled successfully. line name problem success * Link goes to the SOAP API Developer's Guide. if one did. The line number where an error occurred. * Link goes to the SOAP API Developer's Guide. If true. A DeleteApexResult object has the following properties: Name id problem success Type ID* string* boolean* Description ID of the deleted trigger or class. The column where an error occurred. DeleteApexResult This object is returned when the compileAndTest() call returns information about the deletion of a class or trigger. If the compilation or execution of any trigger fails. It contains information about whether or not the compile and run of the specified Apex was successful. out.println("Couldn't compile class p1 because: " + r[0].MethodA(). 633 . CompileClassResult[] r = new CompileClassResult[0].\n" + "}\n" + "}".getProblem()).out.out. see the SOAP API Developer's Guide.compileClasses(new String[]{p1. } if (!r[0]. Sample Code—Java public void compileClassesSample() { String p1 = "public class p1 {\n" + "public static Integer var1 = 0. } } Arguments Name scripts Type string* Description A request that includes the Apex classes and the values for any fields that need to be set for this request.Appendix D: SOAP API and SOAP Headers for Apex compileClasses() compileClasses() Compile your Apex in Developer Edition or sandbox organizations. String p2 = "public class p2 {\n" + "public static Integer var1 = 0. try { r = apexBinding.MethodA().\n" + "public static void methodA() {\n" + " var1 = 1. For more information about the SOAP headers in the API.isSuccess()) { System. Syntax CompileClassResult[] = compileClasses(string[] classList). } catch (RemoteException e) { System.println("An unexpected error occurred: " + e.\n" + "public static void methodA() {\n" + " var1 = 1. p2}). } if (!r[1]. This call supports the DebuggingHeader and the SessionHeader. Production organizations must use compileAndTest().getMessage()).\n" + "}\n" + "public static void methodB() {\n" + " p2.\n" + "}\n" + "}".\n" + "}\n" + "public static void methodB() {\n" + " p1.println("Couldn't compile class p2 because: " + r[1].getProblem()).isSuccess()) { System. Usage Use this call to compile Apex classes in Developer Edition or sandbox organizations. Usage Use this call to execute an anonymous block of Apex. see the SOAP API Developer's Guide. Usage Use this call to compile the specified Apex triggers in your Developer Edition or sandbox organization. * Link goes to the SOAP API Developer's Guide. This call can be executed from AJAX. 634 . For more information about the SOAP headers in the API. This call supports the API DebuggingHeader and SessionHeader. Production organizations must use compileAndTest(). This call supports the DebuggingHeader and the SessionHeader.executeanonymous(string apexcode). Response CompileTriggerResult executeanonymous() Executes a block of Apex. Response CompileClassResult compileTriggers() Compile your Apex triggers in Developer Edition or sandbox organizations. Syntax CompileTriggerResult[] = compileTriggers(string[] triggerList). Arguments Name scripts Type string* Description A request that includes the Apex trigger or triggers and the values for any fields that need to be set for this request. Syntax ExecuteAnonymousResult[] = binding.Appendix D: SOAP API and SOAP Headers for Apex compileTriggers() * Link goes to the SOAP API Developer's Guide. runTests() Run your Apex unit tests. this field contains the stack trace for the failure. If compiled is False. If False. compileProblem compiled exceptionMessage exceptionStackTrace string* line int* boolean* success * Link goes to the SOAP API Developer's Guide. If False. Response ExecuteAnonymousResult[] ExecuteAnonymousResult The executeanonymous() call returns information about whether or not the compile and run of the code was successful. this field contains a description of the problem that caused the compile to fail. If True. the code was successfully compiled. the exceptionMessage and exceptionStackTrace values are not null. access. Arguments Name apexcode Type string* Description A block of Apex. this field contains the exception message for the failure.0 and higher produce a runtime error if you assign a String value that is too long for the field. SOAP API Developer's Guide contains information about security. this field contains the column number of the point where the compile failed. this field contains the line number of the point where the compile failed. and compileProblem fields are not null. the code was successfully executed. An ExecuteAnonymousResult object has the following properties: Name column Type int* string* boolean* string* Description If compiled is False. If success is False. * Link goes to the SOAP API Developer's Guide. If success is False. 635 . line.Appendix D: SOAP API and SOAP Headers for Apex ExecuteAnonymousResult If a component in a package with restricted API access issues this call. If True. Apex classes and triggers saved (compiled) using API version 15. and SOAP headers. If compiled is False. the request is blocked. the column. getMethodName() + ": " + rtf.getStackTrace()).getFailures()) { System.") + ccr.out.out.Profiling). sh). dh.out. } catch (RemoteException e) { System." + rtf. send no emails.getCodeCoverage()) { System.setHeader( new ApexServiceLocator(). This call supports the DebuggingHeader and the SessionHeader.setAllTests(true).getType() + (ccr.getNumLocationsNotCovered() + " locations not covered out of " + ccr.getNumTestsRun()). Unit tests are class methods that verify whether a particular piece of code is working properly. url). see the SOAP API Developer's Guide.getNamespace() == null ? "" : ccr.println("Number of failures: " + res. RunTestsRequest rtr = new RunTestsRequest().runTests(RunTestsRequest request).getCodeCoverage() != null) { for (CodeCoverageResult ccr : res.currentTimeMillis(). apexBinding.getNamespaceURI().getNumFailures()). Use this call to run your Apex unit tests. "SessionHeader".getMessage()). Apex supports the creation and execution of unit tests. rtr. RunTestsResult res = null.println("Number of tests: " + res. and are flagged with the testMethod keyword in the method definition. // Set the debugging header _DebuggingHeader dh = new _DebuggingHeader(). error-free code.getMessage() + "\n" + rtf.out. Usage To facilitate the development of robust.getNamespace() == null ? "" : rtf.getNamespace() + "._setProperty(ApexBindingStub. if (res. System. String url = "url goes here". } System.println("An unexpected error occurred: " + e.getName() + ": " + ccr.getNamespace() + ".getNumLocations()).runTests(rtr).Appendix D: SOAP API and SOAP Headers for Apex runTests() Syntax RunTestsResult[] = binding.getNumFailures() > 0) { for (RunTestFailure rtf : res.println("Failure: " + (rtf.setHeader( new ApexServiceLocator().ENDPOINT_ADDRESS_PROPERTY. For more information about the SOAP headers in the API. Unit test methods take no arguments.setDebugLevel(LogType. // Set the Apex stub with session ID received from logging in with the partner API _SessionHeader sh = new _SessionHeader().println("Code coverage for " + ccr. commit no data to the database.getServiceName(). dh). // Set the URL received from logging in with the partner API to the Apex stub apexBinding.getNamespaceURI(). try { res = apexBinding.getName() + ". } } if (res.") + rtf. long start = System. Sample Code—Java public void runTestsSample() { String sessionId = "sessionID goes here". apexBinding. 636 .getServiceName(). "DebuggingHeader".out. The request also contains this object which specifies information about the Apex to be tested.start) + "ms").Appendix D: SOAP API and SOAP Headers for Apex RunTestsRequest if (ccr. the content of the package to be tested. If the request is sent in a production organization. Since triggers cannot be tested directly.out.currentTimeMillis() . Response RunTestsResult RunTestsRequest The compileAndTest() call contains a request. } Arguments Name request Type RunTestsRequest Description A request that includes the Apex unit tests and the values for any fields that need to be set for this request.out. Do not use after version 10. all unit tests defined for your organization are run. the namespace that contains the unit tests to be run. this property is ignored.getLine()).getLocationsNotCovered()) System. this request is ignored and all unit tests defined for your organization are run.println("Finished in " + (System. If specified. Do not use this property if you specify allTests as true.0. 637 . RunTestsResult The call returns information about whether or not the compilation of the specified Apex was successful and if the unit tests completed successfully. if you execute compileAndTest() in a production organization. A CompileAndTestRequest object has the following properties: Name allTests classes namespace Type boolean* string*[] string Description If allTests is True. You can specify the same or different classes to be tested as being compiled. An array of one or more objects. and all unit tests defined for the organization are run. For earlier. CompileAndTestRequest with information about the Apex to be compiled.println("\tLine " + cl. you must specify a class that calls the trigger. packages string*[] * Link goes to the SOAP API Developer's Guide. they are not included in this object. Also. Instead. } } } System.getNumLocationsNotCovered() > 0) { for (CodeLocation cl : ccr. unsupported releases. as well as the number. The results include both the total number of lines that could have been executed.Appendix D: SOAP API and SOAP Headers for Apex RunTestsResult A RunTestsResult object has the following properties: Name codeCoverage Type CodeCoverageResult[] Description An array of one or more CodeCoverageResult objects that contains the details of the code coverage for the specified unit tests. and column positions of code that was not executed. the line and column of the code not tested. id ID locationsNotCovered CodeLocation[] 638 . this property contains the DML statement locations. line. It contains information about whether or not the compile of the specified Apex and run of the unit tests was successful. A CodeCoverageResult object has the following properties: Name dmlInfo Type CodeLocation[] Description For each class or trigger tested. if there are any. and the total cumulative time spent in these calls. the number of times the code was executed. The number of unit tests that were run. if there are any. The number of failures for the unit tests. An array of one or more RunTestFailure objects that contain information about the unit test failures. The ID of the CodeLocation. The ID is unique within an organization. An array of one or more code coverage warnings for the test run. This can be helpful for performance monitoring. For each class or trigger tested. for each portion of code tested. This can be helpful for performance monitoring. if any code is not covered. An array of one or more RunTestSuccesses objects that contain information about successes. codeCoverageWarnings CodeCoverageWarning[] failures RunTestFailure[] numFailures numTestsRun successes int int RunTestSuccess[] totalTime double CodeCoverageResult The RunTestsResult object contains this object. and the number of times the code was executed. The total cumulative time spent running tests. The name of the class that generated a warning. the method invocation locations. This object has the following properties: 639 . unsupported releases. For each class or trigger tested. This can be helpful for performance monitoring. The name of the class or trigger covered. name namespace numLocations soqlInfo string string int CodeLocation[] soslInfo CodeLocation[] type string CodeCoverageWarning The RunTestsResult object contains this object. This can be helpful for performance monitoring. the number of times this code was executed. this value is null. The namespace that contains the class. and the total cumulative time spent in these calls. the location of SOQL statements in the code. namespace string RunTestFailure The RunTestsResult object returns information about failures during the unit test run. used to specify class or package. For each class tested. and the total cumulative time spent in these calls. In early. if one is specified. Do not use. This can be helpful for performance monitoring. If the warning applies to the overall code coverage. The total number of code locations. the number of times the code was executed. It contains information about the Apex class which generated warnings. The namespace that contained the unit tests. the location of SOSL statements in the code. the number of times this code was executed. if one was specified. This object has the following properties: Name id message name Type ID string string Description The ID of the class which generated warnings. The message of the warning generated.Appendix D: SOAP API and SOAP Headers for Apex RunTestsResult Name methodInfo Type CodeLocation[] Description For each class or trigger tested. and the total cumulative time spent in these calls. The time spent running tests for this operation. The failure message. The name of the class that succeeded. The namespace that contained the class. This can be helpful for performance monitoring. This object has the following properties: Name id methodName name namespace time Type ID string string string double Description The ID of the class which generated the success. This object has the following properties: 640 . type string * Link goes to the SOAP API Developer's Guide.Appendix D: SOAP API and SOAP Headers for Apex RunTestsResult Name id message methodName name namespace stackTrace time Type ID string string string string string double Description The ID of the class which generated failures. Do not use. used to specify class or package. if one was specified. The name of the class that failed. The name of the method that succeeded. RunTestSuccess The RunTestsResult object returns information about successes during the unit test run. CodeLocation The RunTestsResult object contains this object in a number of fields. The namespace that contained the class. if one was specified. The time spent running tests for this failed operation. In early. unsupported releases. The name of the method that failed. The stack trace for the failure. This can be helpful for performance monitoring. returned in the debug log. Valid values include: • NONE • DEBUGONLY • DB • PROFILING • CALLOUT • DETAIL Specifies the type. categories LogInfo[] LogInfo Specifies the type. The values are listed from the least amount of information returned to the most information returned. as well as the amount of information. Specifies the type of information returned in the debug log. The categories field takes a list of these objects. and specifies the level of detail in the debug header. The total cumulative time spent at this location. This can be helpful for performance monitoring. as well as the amount of information returned in the debug log. API Calls compileAndTest()executeanonymous()runTests() Fields Element Name debugLevel Type logtype Description This field has been deprecated and is only provided for backwards compatibility. DebuggingHeader Specifies that the response will contain the debug log in the return header.Appendix D: SOAP API and SOAP Headers for Apex DebuggingHeader Name column line numExecutions time Type int int int double Description The column location of the Apex tested. The line location of the Apex tested. The number of times the Apex was executed in the test run. 641 . Only the Apex_code LogCategory uses the log category levels.3). As well as a set of components.0 and later. This header is available in API version 16. The major and minor numbers increase to a chosen value during every major release. executeanonymous() 642 . API Calls compileAndTest(). The version number has the format majorNumber. a package version encompasses specific behavior. A package version is a number that identifies the set of components uploaded in a package. If a package version is not specified for a package.patchNumber (for example. Publishers can use package versions to evolve the components in their managed packages gracefully by releasing subsequent package versions without breaking existing customer integrations using the package. Valid values are: • Db • Workflow • Validation • Callout • Apex_code • Apex_profiling • All Specifies the amount of information returned in the debug log. Valid log levels are (listed from lowest to highest): • • • • • • • ERROR WARN INFO DEBUG FINE FINER FINEST LogCategoryLevel string PackageVersionHeader Specifies the package version for each installed managed package. 2. The patchNumber is generated and updated only for a patch release.minorNumber.Appendix D: SOAP API and SOAP Headers for Apex PackageVersionHeader Fields Element Name LogCategory Type string Description Specify the type of information returned in the debug log.1. the API client uses the version of the package that is selected in the Version Settings section in Your Name > Setup > Develop > API. compileTriggers(). compileClasses(). A managed package can have several versions with different content and behavior. This header allows you to specify the version used for each package referenced by your API client. 1. A package version is denoted by majorNumber.1. A package version is denoted by majorNumber. for example 2. PackageVersion Specifies a version of an installed managed package.minorNumber.Appendix D: SOAP API and SOAP Headers for Apex PackageVersionHeader Fields Element Name packageVersions Type Description PackageVersion[] A list of package versions for installed managed packages referenced by your API client. It includes the following fields: Field majorNumber Type int int string Description The major version number of a package version. The minor version number of a package version. for example 2. minorNumber namespace 643 . The unique namespace of the managed package.minorNumber. 644 . object-oriented programming language that allows developers to execute flow and transaction control statements on the Force. such as getting all accounts that do not have any open opportunities. In addition.com platform server in conjunction with calls to the Force. Apex enables developers to add business logic to most system events. Apex code can be initiated by Web service requests and from triggers on objects. For more information. You can customize the standard apps to match the way you work. Apex Page See Visualforce Page. or the equivalent in the AJAX Toolkit.” A collection of components such as tabs. App Short for “application.com API. Users assigned to the System Administrator profile have administrator privileges. Anti-Join An anti-join is a subquery on another object in a NOT IN clause in a SOQL query. but that can be compiled and executed through the use of the ExecuteAnonymousResult() API call. and Visualforce pages. see the AJAX Toolkit Developer's Guide. related record updates. Using syntax that looks like Java and acts like database stored procedures. you can package an app and upload it to the AppExchange along with related components such as custom fields.Glossary A |B |C |D |E |F |G |H |I |J |K |L |M |N |O |P |Q |R |S |T |U |V |W |X |Y |Z A Administrator (System Administrator) One or more individuals in your organization who can configure and customize the application. Apex Apex code that does not get stored in Salesforce. Salesforce provides standard apps such as Sales and Call Center. you can make the app available to other Salesforce users from the AppExchange. including button clicks. See also Semi-Join. dashboards. Apex Apex is a strongly typed. and Visualforce pages that address a specific business need. Apex-Managed Sharing Enables developers to programmatically manipulate sharing to support their application’s behavior. AJAX Toolkit A JavaScript wrapper around the API that allows you to execute any API call and access any object you have permission to view from within JavaScript code. Then. Apex-managed sharing is only available for custom objects. You can use anti-joins to create advanced queries. Anonymous Block. and custom objects. custom tabs. reports. C Callout. Beta. Client App An app that runs outside the Salesforce user interface and uses only the Force. Class. These apps treat the platform as a data source. It typically runs on a desktop or mobile device. Apex A template or blueprint from which Apex objects are created. update. and static initialization code. Apex An Apex callout enables you to tightly integrate your Apex with an external service by making a call to an external Web service or sending a HTTP request from Apex code and then receiving the response. A step can apply to all records included in the process. contacts. An approval process also specifies the actions to take when a record is approved. variables. or application provides to allow other computer programs to request services from it and exchange data. library. or first submitted for approval. Application Programming Interface (API) The interface that a computer system. Managed Package In the context of managed packages.com that allows you to browse and share apps and services for the Force. Asynchronous Calls A call that does not return results immediately because the operation may take a long time.com platform. recalled. exception types. Apex classes are modeled on their counterparts in Java. or delete a large number of records asynchronously by submitting a number of batches which are processed in the background by Salesforce. complex operations on many records at a scheduled time using Apex. insert. Classes consist of other classes. user-defined methods. Child Relationship A relationship that has been defined on an sObject that references another sObject as the “one” side of a one-to-many relationship. B Batch Apex The ability to perform long. 645 . An approval process specifies the steps necessary for a record to be approved and who must approve it at each step. It allows you to query. or just records that have certain attributes. See also sObject. See also SOAP API. a beta managed package is an early version of a managed package distributed to a sampling of your intended audience to test it. and tasks have child relationships with accounts. Approval Process An approval process is an automated process your organization can use to approve records in Salesforce. using the development model of whatever tool and platform for which they are designed. Calls in the Metadata API and Bulk API are asynchronous. upsert.com API or Bulk API. In most cases. For example. Bulk API The REST-based Bulk API is optimized for processing large sets of data. opportunities.Glossary AppExchange The AppExchange is a sharing interface from salesforce. rejected. Cookie Client-specific data used by some Web applications to store user and session-specific information. and which are not. such as Yahoo! Maps. Custom Field A field that can be added in addition to the standard fields to customize Salesforce for your organization’s needs. 646 . Use custom controllers when you want your Visualforce page to run entirely in system mode. See also Client App and Native App. for example. Custom Links Custom links are URLs defined by administrators to integrate your Salesforce data with external websites and back-office systems. Visualforce pages can use the standard controllers that come by default with every standard or custom object.com Migration Tool.com IDE or the Force. For example. such as the Force. Salesforce issues a session “cookie” only to record encrypted authentication information for the duration of a specific session. and the MyCustomObject__c component is an instance of a custom object. which does not enforce the permissions and field-level security of the current user. Component. Visualforce A description of the standard and custom Visualforce components that are available in your organization. Component. Controller Extension A controller extension is an Apex class that extends the functionality of a standard or custom controller. Composite App An app that combines native platform functionality with one or more external Web services. A component is described in an XML file and it can be deployed or retrieved using the Metadata API. Controller. Metadata A component is an instance of a metadata type in the Metadata API.Glossary Code Coverage A way to identify which lines of code are exercised by a set of unit tests. <apex:detail>. Custom App See App. This helps you identify sections of code that are completely untested and therefore at greatest risk of containing a bug or introducing a regression in the future. Component Reference. You can access the component library from the development footer of any Visualforce page or the Visualforce Developer's Guide. Visualforce An Apex class that provides a Visualforce page with the data and business logic it needs to run. Composite apps allow for more flexibility and integration with other services. CustomObject is a metadata type for custom objects. but may require running and managing external code. or tools built on top of it. Custom Controller A custom controller is an Apex class that implements all of the logic for a page without leveraging a standard controller. Visualforce includes a number of standard components. Visualforce Something that can be added to a Visualforce page with a set of tags. or you can create your own custom components. Custom Object Custom records that allow you to store information unique to your organization. or they can use custom controllers. Formerly known as Web links. 1.98 for an entry of 2. the number rounds to 4. profile. for example. Note that the system rounds the decimal numbers you enter. as well as create and associate custom data for an organization. or specific user. D Database An organized collection of information. Date Literal A keyword in a SOQL or SOSL query that represents a relative range of time such as last month or next year. –1.45 is rounded to 1. and ordering dependencies (when one object must be deployed before another object). and percent custom fields that indicates the total number of digits you can enter to the right of a decimal point. 4. The underlying architecture of the Force. 647 . updates. currency.com platform includes a database where your data is stored.com platform tool used to import and export data from your Salesforce organization. They are used for authenticated SSL communications with an external web site. Database Table A list of information. See also Object. Apex. See also Hierarchy Custom Settings and List Custom Settings.Glossary Custom Settings Custom settings are similar to custom objects and enable application developers to create custom sets of data. This data can then be used by formula fields. Dependent Field Any custom picklist or multi-select picklist field that displays available values based on the value selected in its corresponding controlling field. for example). For example. Decimal Places Parameter for number. Salesforce uses the round half-up rounding algorithm. about the person. Data State The structure of data in an object at a particular point in time. All custom settings data is exposed in the application cache. which enables efficient access without the cost of repeated queries to the database. There are a number of different kinds of dependencies including mandatory fields. Half-way values are always rounded up.5. For example. dependent objects (parent-child). Data Loader A Force. presented with rows and columns. thing.com platform database. Dependency A relationship where one object's existence depends on that of another. Salesforce Certificate and Key Pair Salesforce certificates and key pairs are used for signatures that verify a request is coming from your organization. or when using your organization as an Identity Provider. You only need to generate a Salesforce certificate and key pair if you're working with an external website that wants verification that a request is coming from a Salesforce organization. if necessary.45 is rounded to –1. validation rules. or concept you want to track. or deletes records from the Force.5. Data Manipulation Language (DML) An Apex method or operation that inserts. if you enter 4. file inclusion (referenced images.99.986 in a field with Decimal Places of 2. and the SOAP API. Deprecated Component A developer may decide to refine the functionality in a managed package over time as the requirements evolve.com. E Email Alert Email alerts are workflow and approval actions that are generated using an email template by a workflow rule or approval process and sent to designated recipients. it is only available to administrators and any users with the “Customize Application” permission. HTML.com provides a full range of resources for platform developers. Enterprise WSDL A strongly-typed WSDL for customers who want to build an integration with their Salesforce organization only. and the ability to obtain limited Force. when developing new features in the Salesforce user interface. There are two kinds of development environments. The detail page of a record allows you to view the information. fully-functional Salesforce organization designed for developers to extend. The downside of the Enterprise WSDL is that it only works with the schema of a single Salesforce organization because it is bound to all of the unique objects and fields that exist in that organization's data model. To move metadata components from a local file system to a Salesforce organization. Detail A page that displays information about a single object record. This may involve redesigning some of the components in the managed package.force. Email templates can be personalized with merge fields. including sample code. an online developer community. Developer Edition accounts are available on developer. sandboxes and Developer Edition organizations. integrate.com platform. and can be written in text. such as a welcome letter to new employees or an acknowledgement that a customer service request has been received. Developer Edition A free. deployment makes any custom objects in the app available to users in your organization. you must select the “Deployed” option to make the functionality visible to other users. A term used in reports to distinguish between summary information and inclusion of all column data for all information in a report. whereas the edit page allows you to modify it.force. toolkits.Glossary Deploy To move functionality from an inactive state to active. or for partners who are using tools like Tibco or webMethods to build integrations that require strong typecasting. and develop with the Force. Developer Force The Developer Force website at developer. Enterprise Edition A Salesforce edition designed for larger. Development Environment A Salesforce organization where you can make configuration changes that will not affect users on the production organization. You can toggle the Show Details/Hide Details button to view and hide report detail information. either Salesforce users or others. but they can deprecate a component in a later package version so that new subscribers do not receive the component. 648 . while the component continues to function for existing subscribers and API integrations. more complex businesses. Email Template A form email that communicates a standard message. Developers cannot delete some components in a Managed . For installed apps.Released package.com platform environments. Before a custom object is deployed. For example. or custom format. The process by which an application or other functionality is moved from development to production. Field A part of an object that holds a specific piece of information. debug and deploy Force. Force. The valid values of the field are restricted to a strict set of possible values.com combines a powerful user interface.com IDE An Eclipse plug-in that allows developers to manage. See also Setter Methods.com Migration Tool A toolkit that allows you to write an Apache Ant build script for migrating Force. read only. You can think of a foreign key as a copy of a primary key from another table. Foreign Key A field whose value is the same as the primary key of another table. and database to allow you to customize and deploy applications in the cloud for your entire enterprise. or editable for users.com platform for building applications in the cloud. F Facet A child of another Visualforce component that allows you to override an area of the rendered parent with the contents of the facet.Glossary Entity Relationship Diagram (ERD) A data modeling tool that helps you organize your data into entities (or objects.com applications in the Eclipse development environment. Methods that return values. Unlimited. author. operating system. all having the same data type. A relationship is made between two tables by matching the values of the foreign key in one table with the values of the primary key in another. and Developer Editions only. visible. Force. Force. Enumeration Field An enumeration is the WSDL equivalent of a picklist field. such as a text or currency value. ERD diagrams for key Salesforce objects are published in the SOAP API Developer's Guide.com platform) and define the relationships between them. G Getter Methods Methods that enable developers to display database and other computed values in page markup.com components between a local file system and a Salesforce organization. Available in Enterprise. as they are called in the Force. Field Dependency A filter that allows you to change the contents of a picklist based on the value of another field. A method access modifier for any method that needs to be referenced outside of the application. 649 .com The salesforce. Force. Field-Level Security Settings that determine whether fields are hidden. either in the SOAP API or by other Apex code. Global Variable A special merge field that you can use to reference data in your organization. or “lowest. They behave as proxy servers running on your local machine and allow you to inspect and author individual requests. promote favorite enhancements.com. are overridden by user settings. profile. In the hierarchy.salesforce. HTTP Debugger An application that can be used to identify and inspect SOAP requests that are sent from the AJAX Toolkit. The hierarchy logic checks the organization. ISO Code The International Organization for Standardization country code. Gregorian Year A calendar based on a 12-month structure used throughout much of the world. H Hierarchy Custom Settings A type of custom setting that uses a built-in hierarchical logic that lets you “personalize” settings for specific profiles or users. interact with product managers and other customers.com platform runs on multiple instances. 650 . which. Integrated Development Environment (IDE) A software application that provides comprehensive facilities for software developers including a source code editor. in turn. Instance The cluster of software and hardware represented as a single logical server that hosts an organization's data and runs their applications. IdeaExchange A forum where salesforce. I ID See Salesforce Record ID. but data for any single organization is always consolidated on a single instance. Import Wizard A tool for importing data into your Salesforce organization. settings for an organization are overridden by profile settings. Integration User A Salesforce user defined solely for client apps or integrations. accessible from Setup. and preview what salesforce.Glossary Governor Limits Apex execution limits that prevent developers who write inefficient code from monopolizing the resources of other Salesforce users. Also referred to as the logged-in user in a SOAP API context. The Force.com customers can suggest new product concepts. and integration with source code control systems.com is planning to deliver in future releases. Visit IdeaExchange at ideas. which represents each country by two letters. and user settings for the current user and returns the most specific.” value. testing and debugging tools. Google matches a search phrase to your keywords. If you use a particular set of data frequently within your application. not Default Locale. currency. Unlimited. causing your advertisement to trigger on Google. for example. L Length Parameter for custom text fields that specifies the maximum number of characters (up to 255) that a user can enter in the field. In Personal and Group Editions. Locale The country or geographic region in which the user is located. a user’s individual Locale setting overrides the organization’s Default Locale setting. The list views you can select to display in the console are the same list views defined on the tabs of other objects. K Key Pair See Salesforce Certificate and Key Pair. List View A list display of items (for example. For example. You cannot create a list view within the console. and percent fields that specifies the number of digits you can enter to the left of the decimal point. Enterprise. you may have a custom object called “Bug” that relates to the standard case object such that a bug could be related to multiple cases and a case could also be related to multiple bugs. You create and manage your keywords in Google AdWords. In Professional. 651 .98 for an entry of 3. Local Name The value stored for the field in the user’s or account’s language. international dialing prefixes. 123.Glossary J Junction Object A custom object with two master-detail relationships. Parameter for number. and catalog numbers for products. the organization-level locale field is called Locale. for example. you can model a “many-to-many” relationship between two objects. and Developer Edition organizations. access is low-cost and efficient: you don't have to use SOQL queries that count against your governor limits. Keyword Keywords are terms that you purchase in Google AdWords. The local name for a field is associated with the standard name for that field. In the Console tab. the list view is the top frame that displays a list view of records based on specific criteria. Data in list settings does not vary with profile or user. accounts or contacts) based on specific criteria. dates in the English (United States) locale display as 06/30/2000 and as 30/06/2000 in the English (United Kingdom) locale. Using a custom junction object. Salesforce provides some predefined views. The setting affects the format of date and number fields. List Custom Settings A type of custom setting that provides a reusable set of static data that can be accessed across your organization. Examples of list data include two-letter state abbreviations. Because the data is cached. but is available organization-wide. putting that data in a list custom setting streamlines access to it. a lookup field allows users to click a lookup icon and select another record from a popup window.” with no code required. a package must be managed. allowing the managed package to be upgraded later. Alternatively. forms. Manual Sharing Record-level access rules that allow record owners to give read and edit permissions to other users who might not have access to the record any other way. common infrastructure and code base. Unmanaged packages do not include locked components and cannot be upgraded. objects. appearance. For example. Many-to-Many Relationship A relationship where each side of the relationship can have many children on the other side. In addition. 652 . M Managed Package A collection of application components that is posted as a unit on the AppExchange and associated with a namespace and possibly a License Management Organization. Many-to-many relationships are implemented through the use of junction objects.Glossary Long Text Area Data type of custom field that allows entry of up to 32. Metadata-Driven Development An app development model that allows apps to be defined as declarative “blueprints. cases have a lookup relationship with assets that lets you associate a particular asset with a case. MVC (Model-View-Controller) A design paradigm that deconstructs applications into components that represent data (the model). On the associated record. managed packages obfuscate certain components (like Apex) on subscribing organizations to protect the intellectual property of the developer. by default Salesforce clears the lookup field. Metadata Information about the structure. Lookup Relationship A relationship between two records so you can associate records with each other. To support upgrades. and more—are defined by metadata. you can prevent records from being deleted if they’re in a lookup relationship.com Metadata API calls. This type of relationship affects record deletion. Multitenancy An application model where all users and apps share a single. ways of displaying that data in a user interface (the view). An organization can create a single managed package that can be downloaded and installed by many different organizations. Metadata WSDL A WSDL for users who want to use the Force. you can then display a related list to show all of the records that have been linked to it. workflows. For example.com uses XML to describe metadata. On one side of the relationship. security. Master-Detail Relationship A relationship between two different types of records that associates the records with each other. and functionality of an organization and any of its parts. Apps built on the platform—their data models. and ways of manipulating that data with business logic (the controller). and makes the lookup relationship field required on the page layout.000 characters on separate lines. Force. If a lookup field references a record that has been deleted. accounts have a master-detail relationship with opportunities. Managed packages differ from unmanaged packages by having some locked components. a one. Native apps do not require any external services or infrastructure. It displays on custom object record home (overview). but they need extra permissions to edit one. For each object. For example. For example. and is separate from all other organizations. a contact or case) is assigned. Outbound messaging is configured in the Salesforce setup menu.com. as well as list views and related lists. detail. to all unique component names in your Salesforce organization. Outbound Call Any call that originates from a user to a number outside of a call center in Salesforce CRM Call Center. Outbound Message An outbound message is a workflow.Glossary N Namespace In a packaging context. followed by two underscores (“__”). and edit pages. An organization is the virtual space provided to an individual customer of salesforce. you might have a case record to store the information about Joe Smith's training inquiry and another case record to store the information about Mary Johnson's configuration issue. Organization A deployment of Salesforce with a defined set of licensed users. O Object An object allows you to store information in your Salesforce organization. your organization will have multiple records that store the information about specific instances of that type of data. For example. an account may have one or more related contacts. An outbound message sends the data in the specified fields in the form of a SOAP message to the endpoint. You can create a listener for the messages using the SOAP API.com. Then you must configure the external endpoint. the case object allow you to store information regarding customer inquiries. For example. Object-Level Security Settings that allow an administrator to hide whole objects from users so that they don't know that type of data exists. or milestone action that sends the information you specify to an endpoint you designate. Organization-Wide Defaults Settings that allow you to specify the baseline level of data access that a user has in your organization. One-to-Many Relationship A relationship in which a single object is related to many other objects. you can set organization-wide defaults so that any user can see any record of a particular object that is enabled via their object permissions. Owner Individual user to which a record (for example. 653 . approval. similar to a domain name. Native App An app that is built exclusively with setup (metadata) configuration on Force.to 15-character alphanumeric identifier that distinguishes your package and its contents from packages of other developers onAppExchange. Your organization includes all of your data and applications. The object is the overall definition of the type of information you are storing. Salesforce automatically prepends your namespace prefix. Object-level security is specified with object permissions. such as an external service. Object-Level Help Custom help text that you can provide for any custom object. you can add new variables or change the body of an Apex class. but you may not add. which typically involves editing the XML.1. Partner WSDL A loosely-typed WSDL for customers. Packages can exhibit different behavior for different versions. A package version has more significance for managed packages. while ensuring subscribing organizations that there are no visible behavior changes to the package. deprecate. After you install a package.Glossary P PaaS See Platform as a Service. With this WSDL. the developer is responsible for marshaling data in the correct object representation. Contrast this with the Enterprise WSDL. a component. Publishers can use package versions to evolve the components in their managed packages gracefully by releasing subsequent package versions without breaking existing customer integrations using the package. and ISVs who want to build an integration or an AppExchange app that can work across multiple Salesforce organizations. Unmanaged packages are not upgradeable. You use packages to bundle an app along with any related components so that you can upload them to AppExchange together. which is strongly typed. Package Installation Installation incorporates the contents of a package into your Salesforce organization. See also Patch and Patch Development Organization. or remove any of its methods. See also Patch Development Organization and Package Version. Components can include but are not limited to: • Standard or custom fields • Standard or custom objects • Visualforce pages • Apex code Permissions and preferences can include but are not limited to: • Divisions • Multicurrency • Record types Package Version A package version is a number that identifies the set of components uploaded in a package. 654 . or preference that is required for the component to be valid.com components and applications that are made available to other organizations through the AppExchange. Patches are tracked by a patchNumber appended to every package version. Package A group of Force. However. so each package version is simply a set of components for distribution. partners. A package on the AppExchange can include an app. you may need to deploy components in the package to make it generally available to the users in your organization.3). 2. The major and minor numbers increase to a chosen value during every major release. Package Dependency This is created when one component references another component. Patch A patch enables a developer to change the functionality of existing components in a managed package. the developer is also freed from being dependent on any particular data model or Salesforce organization. The patchNumber is generated and updated only for a patch release.patchNumber (for example. or a combination of the two. For example.minorNumber. The version number has the format majorNumber. permission. and uploaded. typically after a '?' character. methods and variables that are available to other Apex code. software. Record ID See Salesforce Record ID. The PaaS vendor also takes responsibility for the daily maintenance. For example.Glossary Patch Development Organization The organization where patch versions are developed. Patch development organizations are created automatically for a developer organization when they request to create a patch. and support of the deployed application and each customer's data. See also Patch and Package Version.salesforce. The relationship is made between two tables by matching the values of the foreign key in one table with the values of the primary key in another. Platform as a Service (PaaS) An environment where developers use programming tools offered by a service provider to create applications and deploy them in a cloud. Professional Edition A Salesforce edition designed for businesses who need full-featured CRM functionality. The PaaS vendor provides an API for creating and extending specialized applications. configure. Platform Edition A Salesforce edition based on either Enterprise Edition or Unlimited Edition that does not include any of the standard Salesforce CRM apps. The service alleviates the need for programmers to install. For example: http://na1. Production Organization A Salesforce organization that has live users accessing data. Prototype The classes. Primary Key A relational database concept. This field is called the primary key. maintained. operation. Each table in a relational database has a field in which the data value uniquely identifies the record. Services can be delivered using the PaaS environment to any market segment. 655 . Query String Parameter A name-value pair that's included in a URL. Personal Edition Product designed for individual sales representatives and single users. and related IT resources. Q Query Locator A parameter returned from the query() or queryMore() API call that specifies the index of the last result record that was returned. such as Sales or Service & Support. “John Jones” might be the name of a contact record. The application is hosted as a service and provided to customers via the Internet.com/001/e?name=value R Record A single instance of a Salesforce object. and maintain the applications on their own hardware. the value is represented as a link to a detail view of the record. Final Rejection Actions. Running User Each dashboard has a running user. Relationship Query In a SOQL context. Roll-Up Summary Field A field type that automatically provides aggregate values from child records in a master-detail relationship. Recycle Bin A page that lets you view and restore deleted information. Parent-to-child and child-to-parent syntax differs in SOQL queries. and can still be edited. Record Name A standard field on all Salesforce objects. but then restrict the records that the user is allowed to see. whose security settings determine which data to display in a dashboard. won't be allowed to create them. Salesforce automatically locks records that are pending approval.com application. Existing s-controls will remain unaffected. so that each user sees the dashboard according to his or her own access level. Matching values in a specified field in both objects are used to link related data. all dashboard viewers see data based on the security settings of that user—regardless of their own personal security settings. Access the Recycle Bin by using the link in the sidebar. Record Locking Record locking is the process of preventing users from editing a record. to edit locked records. a query that traverses the relationships between objects to identify and return results. After March 2010 organizations that have never created s-controls. regardless of the organization-wide sharing model settings. A record name can be either free-form text or an autonumber field. If the running user is a specific user. Whenever a record name is displayed in a Force. you can set the running user to be the logged-in user. Users must have the “Modify All” object-level permission for the given object. and Recall Actions related lists contain Record Lock actions by default.Glossary Record-Level Security A method of controlling data in which you can allow a particular user to view and edit an object. regardless of field-level security or sharing settings. a relationship allows you to find out which people work at the company. For dynamic dashboards. Record Name does not have to be a unique value. Relationship A connection between two objects. S-Control Note: S-controls have been superseded by Visualforce pages. if one object stores data about companies and another object stores data about people. The Initial Submission Actions. used to create related lists in page layouts and detail levels in reports. as well as new organizations. S SaaS See Software as a Service (SaaS). You cannot edit this default action for initial submission and recall actions. Role Hierarchy A record-level security setting that defines different levels of users such that users at higher levels can view and edit information owned by or shared with users beneath them in the role hierarchy. or the “Modify All Data” permission. Final Approval Actions. for example. 656 . an Active-X control. Access Setup through the Your Name > Setup link at the top of Salesforce pages. or a custom HTML Web form. • Manual Sharing—allows individual users to share records with other users or groups. for example a Java applet.com that allows you to make calls to external Web services from within Apex. You can create multiple sandboxes in separate environments for a variety of purposes. such as getting all contacts for accounts that have an opportunity with a particular record type. which are terms for the unique ID of a Salesforce record. The default is 120 minutes (two hours). The Session ID prevents a user from having to log in again every time he or she wants to perform another action in Salesforce. The inactivity timer is reset to zero if a user takes an action in the Web interface or makes an API call. Session ID An authentication token that is returned when a user successfully logs in to Salesforce. • Role Hierarchy—defines different levels of users such that users at higher levels can view and edit information owned by or shared with users beneath them in the role hierarchy. Setter Methods Methods that assign values. Salesforce SOA (Service-Oriented Architecture) A powerful capability of Force. Semi-Join A semi-join is a subquery on another object in an IN clause in a SOQL query. There are different ways to share data: • Sharing Model—defines the default organization-wide access levels that users have to each other’s information and whether to use the hierarchies when determining access to data. or when using your organization as an Identity Provider. See also Anti-Join.com applications. You can use semi-joins to create advanced queries. regardless of the organization-wide sharing model settings. Sandbox Organization A nearly identical copy of a Salesforce production organization. Session Timeout The period of time after login before a user is automatically logged out. Salesforce Record ID A unique 15.Glossary Custom Web content for use in custom links. Setup An administration area where you can customize and define Force. 657 . They are used for authenticated SSL communications with an external web site. See also Getter Methods. Sessions expire automatically after a predetermined length of inactivity. an Excel file. Sharing Allowing other users to view or edit information you own. Different from a record ID or Salesforce ID. without compromising the data and applications in your production environment. Salesforce Certificate and Key Pair Salesforce certificates and key pairs are used for signatures that verify a request is coming from your organization. Custom s-controls can contain any type of content that you can display in a browser. You only need to generate a Salesforce certificate and key pair if you're working with an external website that wants verification that a request is coming from a Salesforce organization. which can be configured in Salesforce by clicking Your Name > Setup > Security Controls. • Sharing Rules—allow an administrator to specify that all information created by users within a given group or role is automatically shared to the members of another group or role.or 18-character alphanumeric string that identifies a single record in Salesforce. such as testing and training. Services can be delivered using the SaaS model to any market segment. Sharing Model Behavior defined by your administrator that determines default access by users to different types of records. System Log Part of the Developer Console. activities. Sites Force. See Apex-Managed Sharing. The body of the System Log displays system resource information. SOAP API A SOAP-based Web services application programming interface that provides access to your Salesforce organization's information. campaigns. contacts. Sharing Rule Type of default sharing created by administrators.com platform. Administrators can enable tags for accounts. and support of the application and each customer's data. The SaaS vendor takes responsibility for the daily maintenance. cases. Enter the code you want to test at the bottom of the window and click Execute. SOSL (Salesforce Object Search Language) A query language that allows you to perform text-based searches using the Force. Allows users in a specified group or role to have access to all information created by users within a given group or role. T Tag In Salesforce. SOAP (Simple Object Access Protocol) A protocol that defines a uniform way of passing XML-encoded data. such as how long a line took to execute or how many database calls were made. assets. the console also displays debugging information. sObject Any object that can be stored in the Force. and maintain applications with their own hardware. configure. 658 . Software as a Service (SaaS) A delivery model where a software application is hosted as a service and provided to customers via the Internet. operation.com database.com platform. and related IT resources. SOQL (Salesforce Object Query Language) A query language that allows you to construct simple but powerful query strings and to specify the criteria that should be used to select data from the Force. The service alleviates the need for customers to install. Standard Object A built-in object included with the Force. If the code did not run to completion. a word or short phrases that users can associate with most records to describe and organize their data in a personalized way.Glossary • Apex-Managed Sharing—enables developers to programmatically manipulate sharing to support their application’s behavior. software.com API.com Sites enables you to create public websites and applications that are directly integrated with your Salesforce organization—without requiring users to log in with a username and password. a separate window console that can be used for debugging code snippets. You can also build custom objects to store information that is unique to your app. contracts. 659 . but are documents that specify what your unit tests should do. tasks. Transaction. a Visualforce page. Test methods take no arguments.com's flagship solution for maximizing CRM success and extending that success across the entire enterprise through the Force. the entire transaction is rolled back and no data is committed to the database.salesforce. For example. or a custom Web service method.com IDE. they process several records at once. or other resource on the Internet. UAT is one of the final stages before deployment to production. Unlimited Edition Unlimited Edition is salesforce. events. http://www. Test cases are not actual unit tests. Test Case Coverage Test cases are the expected real-world scenarios in which your code will be used. rather than just one record at a time. Unmanaged Package A package that cannot be upgraded or controlled by its developer. See also Code Coverage and Unit Test. See also Sandbox Organization. or deleted from the database. reports. opportunities. U Unit Test A unit is the smallest testable part of an application. or if an error occurs in one operation. leads. High test case coverage means that most or all of the real-world scenarios you have identified are implemented as unit tests. See also Test Method. notes.com platform. User Acceptance Testing (UAT) A process used to confirm that the functionality meets the planned requirements. document. documents. All DML operations in a transaction either complete successfully. and can be executed by the runTests() system method either through the command line or in an Apex IDE. an anonymous block of code. and any custom objects (except relationship group members) Tags can also be accessed through the SOAP API. updated. Every trigger runs with a set of context variables that provide access to the records that caused the trigger to fire. Users can view a list of all files or Web links that belong to a particular tag or filter search results based on a tag or tags. a descriptive label that helps classify and organize content across libraries. Trigger A piece of Apex that executes before or after records of a particular type are inserted. Trigger Context Variable Default variables that provide access to information about the trigger and the records that caused it to fire. In Salesforce CRM Content.com. such as the Force. Test Organization A Salesforce organization used strictly for testing. A unit test operates on that piece of code to make sure it works correctly.Glossary dashboards. The boundary of a transaction can be a trigger. and all triggers run in bulk mode—that is. solutions. Test Method An Apex class method that verifies whether a particular piece of code is working properly. usually a method. URL (Uniform Resource Locator) The global address of a website. commit no data to the database. Apex An Apex transaction represents a set of operations that are executed as a single unit. a class method. and Visualforce pages and components. Visualforce Lifecycle The stages of execution of a Visualforce page. Visualforce Controller See Controller. View The user interface in the Model-View-Controller model. are written in different languages. tag-based markup language that allows developers to easily define custom pages and components for apps built on the platform. and can be associated with a CSS style. Apex classes and triggers. or developers can associate their own logic with a controller written in Apex. Web service methods must be defined in a global class. even if they run on different platforms. fields and calls. but they can also modify or capture data. The components can either be controlled by the same logic that is used in standard Salesforce pages. a related list. Web Services API A Web services application programming interface that provides access to your Salesforce organization's information. Version A number value that indicates the release of an item. Workflow and Approval Actions Workflow and approval actions consist of email alerts. field updates. like a mash-up with a third-party application. They can be rendered in several ways. WebService Method An Apex class method or variable that can be used by external systems.Glossary V Validation Rule A rule that prevents a record from being saved if it does not meet the standards that are specified. Visualforce A simple. including how the page is created and destroyed during the course of a user session. such as a section of a page. Visualforce pages present information relevant to your organization. Typically. and outbound messages that can be triggered by a workflow rule or approval process. 660 . View State Where the information necessary to maintain the state of the database between requests is saved. Visualforce. W Web Service A mechanism by which two applications can easily exchange data over the Internet. or a field. Items that can have a version include API objects. tasks. such as a PDF document or an email attachment. or are geographically remote from each other. defined by Visualforce. See also SOAP API and Bulk API. Visualforce Page A web page created using Visualforce. Each tag corresponds to a coarse or fine-grained component. keeps program logic in one place. Your development environment's SOAP client uses the Salesforce Enterprise WSDL or Partner WSDL to communicate with Salesforce using the SOAP API. A wrapper class makes an integration more straightforward to develop and maintain. which is a JavaScript wrapper around the Salesforce SOAP API. and querying and batching records. wrapper classes such as CCritical Section in the CTI Adapter for Salesforce CRM Call Center. 661 . X XML (Extensible Markup Language) A markup language that enables the sharing and transportation of structured data. WSDL (Web Services Description Language) File An XML file that describes the format of messages you send and receive from a Web service. or wrapper classes created as part of a client integration application that accesses Salesforce using the SOAP API. All Force. Examples of wrapper classes in Salesforce include theAJAX Toolkit. managing sessions. Z No Glossary items for this entry.com components that are retrieved or deployed through the Metadata API are represented by XML definitions.Glossary Wrapper Class A class that abstracts common functions such as logging in. and affords easy reuse across components. Y No Glossary items for this entry. Web services available for Apex 624 compileAndTest 596. 633 compileTriggers 601. Web services ApexTestQueueItem 154 ApexTestResult 154 AppExchange creating packages 569.Index Index A Abstract definition modifier 103 Access modifiers 111 Action class instantiation 471 methods 472 understanding 471 addError(). 248 how it works 3 introducing 1 invoking 77 learning 7 managed sharing 186 overview 2 testing 146–147 when to use 11 Apex REST methods 414 Apex REST API methods exposing data 236 ApexTestQueueItem object 625 ApexTestResult object 626 API calls. 629 compileClasses 601.UserData class 564 B Batch Apex database object 385 interfaces 177 schedule 93 using 177 Batch size. 601. 634 custom 227 API calls.RegistrationHandler interface createUser method 564 updateUser method 564 Auth. SOQL query for loop 62 Before triggers 78 Best practices Apex 92 Apex scheduler 98 batch Apex 185 programming 92 SOQL queries 69 testing 156 triggers 92 WebService keywords 227 Binds 71 Blob data type 26 methods 279 Boolean data type 26 662 . triggers 91 After triggers 78 Aggregate functions 66 AJAX support 99 ALL ROWS keyword 73 Anchoring bounds 500 Annotations deprecated 127 future 127 HttpDelete 133 HttpGet 134 HttpPatch 134 HttpPost 134 HttpPut 134 isTest 128 ReadOnly 131 RemoteAction 132 RestResource 133 understanding 126 Anonymous blocks transaction control 74 understanding 98 Answers class 546 Ant tool 596 AnyType data type 26 Apex designing 92 flow data type conversions 585 from WSDL 246. 591 managed package versions 220–221 Approval processes approval methods 374 example 539 overview 539 ProcessRequest class 540 ProcessResult class 541 ProcessSubmitRequest class 541 ProcessWorkitemRequest class 542 Arrays and lists 34 Assignment statements 57 Async Apex 127 Asynchronous callouts 127 Auth. 635 transaction control 74 when to use 11 API objects. Web services (continued) executeanonymous 634 executeAnonymous 98 retrieveCode 599 runTests 155.AuthToken class getAccessToken method 564 getAccessTokenMap method 564 Auth. PluginResult 582 ProcessRequest 540 ProcessResult 541 ProcessSubmitRequest 541 ProcessWorkitemRequest 542 properties 115 security 139 selectOption 490 shadowing names 139 site 554 standardController 492 standardSetController 494 support 543 TimeZone 437 type resolution 143 understanding 102 UserData 564 using constructors 109 variables 106 Visualforce 123 with sharing 124 without sharing 124 XmlNode 535 Client certificates 252 663 .PluginDescribeResult.OutputParameter sample for lead conversion 585 Process. 137 defining from a WSDL 241 582 Process.InputParameter class 579–580.PluginDescribeResult 579–580.OutputParameter class 579–580. 516 Callouts asynchronous 127 defining from a WSDL 241 execution limits 214 HTTP 251 invoking 240 limit methods 406 limitations 254 limits 254 remote site settings 241 timeouts 254 Calls runTests 155 Capturing groups 500.InputParameter sample for lead conversion 585 Process.PluginDescribeResult.PluginDescribeResult. C Callout testing 514. 503 Case sensitivity 48 Cases class 545 Casting collections 136 understanding 134 Certificates generating 252 HTTP requests 254 SOAP 253 using 252 Chaining.PluginRequest 581 Process. 248 Http 510 HttpRequest 510 HttpResponse 512 ideas 547 IdeaStandardController 473 IdeaStandardSetController 476 inbound email 464 interfaces 117 IsValid flag 137 KnowledgeArticleVersionStandardController 480 matcher 498 message 484 messaging 452 methods 107 naming conventions 139 pageReference 485 pattern 498 precedence 142 Process. 582 Process. using with regular expressions 500 Bulk processing and triggers retry logic and inserting records 84 understanding 83 BusinessHours class 543 Classes (continued) defining methods 107 differences with Java 136 Document 533 email 452 EncodingUtil 525 example 103 exception 469 from WSDL 246. 582 Process. constructor 122 Change sets 595 Character escape sequences 26 Chatter API 562 Chunk size. SOQL query for loop 62 Class step by step walkthrough 18–21.Index Boolean (continued) methods 280 Bounds.PluginDescribeResult sample for lead conversion 585 Process.PluginDescribeResult. 23 Classes action 471 annotations 126 answers 546 Apex 451 API version 144 AuthToken 564 BusinessHours 543 Cases 545 casting 134 collections 136 community 545 constructors 109 cookie 559 Crypto 519 declaring variables 106 defining 102. BatchableContext 178 Date data type 26 methods 281 Datetime data type 26 methods 284 Deadlocks. 634 Components behavior versioning 222–223 Compound expressions 50 Connect in Apex 562 Constants about 48 defining 121 Constructors chaining 122 using 109 Context variables considerations 82 trigger 80 Controllers maintaining view state 123 transient keyword 123 Controllers.com IDE 595 understanding 594 using change sets 595 using Force. Visualforce custom 471 extending 471 understanding 471 Conventions 12 Conversions 46 ConvertLead database method 258 Cookie class 559 Crypto class 519 Custom labels 30 Custom settings examples 367 methods 364 Database (continued) error object methods 389 Database methods convertLead 258 delete 261 insert 263 system static 375 undelete 267 update 269 upsert 271 Database objects methods 385–386 understanding 385–386 Database. methods 353 Describe field set result. 193 Database. methods 361 Describe information access all fields 167 access all sObjects 166 permissions 163 understanding 163 Describe results field sets 361 fields 165. 633 compileTriggers call 601. 353 sObjects 164 Developer Console anonymous blocks 98 using 203 Developer Edition 4 D Data Categories methods 340 Data types converting 46 primitive 26 sObject 29 understanding 26 Database EmptyRecycleBinResult 389 664 .Index Code security 616 system context 124 using sharing 124 Collections casting 136 classes 136 iterating 44 iteration for loops 61 lists 33 maps 33 sets 33 size limits 214 Comments 57 Community class answers 546 Comparable Interface compareTo method 567 compileAndTest call See also deploy call 597 compileClasses call 601. retaining 199 Debugging API calls 212 classes created from WSDL documents 251 log 199 Decimal data type 26 methods 289 rounding modes 293 Declaring variables 47 Defining a class from a WSDL 241 Delete database method 261 Delete statement 261 DeleteResult object 262 deploy call 597 Deploying additional methods 601 Force. avoiding 74 Debug console 203 Debug log.Batchable 177.com Migration Tool 596 Deprecated annotation 127 Deprecating 221 Describe field result. Plugin Implementation for Lead Conversion 585 Flow.PluginDescribeResult 582 Process. deploying Apex 594 Enums methods 339 understanding 44 Error object DML 389 665 . 634 Execution governors email warnings 219 understanding 214 Execution order. triggers 87 Expressions extending sObject and list 56 operators 50 overview 49 regular 498.TextAttachment object 468 InboundEmailResult object 468 InboundEnvelope object 468 understanding 464 EmailException methods 451 EmptyRecycleBinResult methods 389 EncodingUtil class 525 Encryption 519 Enterprise Edition.Index Development process 4 security 616 DML operations behavior 276 convertLead 258 error object 389 exception handling 278 execution limits 214 limit methods 406 understanding 257 unsupported sObjects 275 DML statements delete 261 insert 263 merge 266 undelete 267 update 269 upsert 271 DMLException methods 451 DMLOptions methods 386 Do-while loops 59 Document class 533 Documentation typographical conventions 12 DOM 533 Double data type 26 methods 295 Dynamic Apex foreign keys 173 understanding 162 Dynamic DML 173 Dynamic SOQL 172 Dynamic SOSL 172 Error object (continued) methods 389 Escape sequences.PluginResult 582 Sample Process. deploying Apex 601 Email attachments 461 inbound 464 outbound 452.Plugin Interface 579–580 Process.BinaryAttachment object 467 InboundEmail.PluginRequest 581 Process.com managed sharing 186 E Eclipse. 353 see also sObjects 65 that cannot be modified by triggers 90 tokens 165 validating 32 final keyword 48. 449 uncaught 213 understanding 75 variables 471 executeanonymous call 98. 501 understanding 49 F Features.Interview methods 497 For loops list or set iteration 61 SOQL locking 74 SOQL queries 62 traditional 61 understanding 60 FOR UPDATE keyword 73 Force. triggers 79 Exceptions class 469 constructing 469 DML 278 methods 450 throw statements 75 trigger 91 try-catch-finally statements 75 types 75. 236 Fields access all 167 accessing 30 accessing through relationships 31 describe results 165. character 26 Events.Header object 467 InboundEmail. 121 Flow data type conversions 585 Process. new 12 Field sets describe results 361 Field-level security and custom API calls 227. 461 Email service InboundEmail object 466 InboundEmail. 569 InstallHandler 569 Iterable 118 Iterator 118 Schedulable 93 Support. SOQL query 71 InboundEmail object 465–466 InboundEmail. dereferencing 65 Functional tests for SOSL queries 152 running 153 understanding 148 Future annotation 127 IdeaStandardSetController class (continued) methods 476 understanding 476 Identifiers. 114 methods 112–113 variables 112–113 instanceof keyword 121 Integer data type 26 methods 298 Interfaces Apex 562 Auth. 137 Iterators custom 118 Iterable 119 using 119 G Get accessors 115 Global access modifier 103. 111 Governors email warnings 219 execution 214 limit methods 406 Groups.com IDE. reserved 614 IDEs 8 If-else statements 58 In clause. deploying Apex 595 Force.BinaryAttachment object 467 InboundEmail. 114 static 112.Index Force. 114 using 114 Inline SOQL queries locking rows for 73 returning a single record 69 Insert database method 263 Insert statement 263 InstallHandler interface onInstall method 569 Instance initialization code 112.Header object 467 InboundEmail.com Migration Tool additional deployment methods 601 deploying Apex 596 Foreign keys and SOQL queries 70 Formula fields. 23 Hierarchy custom settings examples 368 How to invoke Apex 77 Http class testing 514 HTTP requests using certificates 254 HttpCalloutMock interface 514 HttpCalloutMock Interface respond method 569 HttpDelete annotation 133 HttpGet annotation 134 HttpPatch annotation 134 HttpPost annotation 134 HttpPut annotation 134 HttpRequest class 510 HttpResponse class 512 I ID data type 26 Methods 296 Ideas class 547 IdeaStandardController class instantiation 473 methods 474 understanding 473 IdeaStandardSetController class instantiation 476 666 .RegistrationHandler 564 Comparable 567 HttpCalloutMock 514.TextAttachment object 468 InboundEmailResult object 468 InboundEnvelope object 468 Initialization code instance 112.EmailTemplateSelector 571 UninstallHandler 591 WebServiceMock 593 Invoking Apex 77 isAfter trigger variable 80 isBefore trigger variable 80 isDelete trigger variable 80 isExecuting trigger variable 80 isInsert trigger variable 80 IsTest annotation 128 isUndeleted trigger variable 80 isUpdate trigger variable 80 IsValid flag 84. capturing 500 H Headers PackageVersionHeader 642 Heap size execution limits 214 limit methods 406 Hello World example understanding 18–21. Apex 11 Limits code execution 214 code execution email warnings 219 determining at runtime 406 methods 151. debug 199 667 . SOQL query 71 Limitations. SOQL query for loop 62 Lists about 33 array notation 34 defining 33 expressions 56 iterating 44 methods 325 sObject 34 sorting 35 Literal expressions 49 Local variables 112 Locking statements 73 Log.Index J JSON deserialization 389 methods 389–390 serialization 389 JSONGenerator methods 394 JSONParser methods 397 Long data type 26 methods 299 Loops do-while 59 execution limits 214 see also For loops 60 understanding 59 while 60 K kbManagement methods 550 Keywords ALL ROWS 73 final 48. 406 List iteration for loops 61 List size. 121 FOR UPDATE 73 instanceof 121 reserved 614 super 121 testMethod 148 this 122 transient 123 webService 227 with sharing 124 without sharing 124 KnowledgeArticleVersionStandardController class methods 481 understanding 480 M Managed packages AppExchange 141 package versions 221 version settings 143 versions 220–223 Managed sharing 186 Manual sharing 186 Maps creating from sObject arrays 41 equals and hashcode methods 41 iterating 44 methods 331 understanding 40 Matcher class bounds 500 capturing groups 500 example 500 methods 503 regions 499 searching 499 understanding 498 using 498 Matcher methods See also Pattern methods 503 Math methods 409 Merge statements triggers and 86 understanding 266 Message class instantiation 484 methods 484 severity enum 484 understanding 484 Message severity 484 Metadata API call deploy 597 Methods access modifiers 111 action 472 Apex REST 414 ApexPages 373 approval 374 blob 279 boolean 280 custom settings 364 data Categories 340 date 281 datetime 284 decimal 289 DescribeSObjectResult object 349 L L-value expressions 49 Language concepts 13 constructs 25 LeadConvertResult object 260 Learning Apex 7 Limit clause. primitives 26 668 . 591 Packages. Visualforce 471 Parameterized typing 41 Parent-child relationships SOQL queries 70 understanding 49 Passed by value. namespaces 141 PackageVersionHeader headers 642 PageReference class instantiation 485 methods 485 navigation example 489 query string example 489 understanding 485 Pages.Interview 497 ID 296 IdeaStandardController 474 IdeaStandardSetController 476 instance 112–113 integer 298 JSON 389–390 JSONGenerator 394 JSONParser 397 kbManagement 550 KnowledgeArticleVersionStandardController 481 limits 406 list 325 long 299 map 40. 335 setFixedSearchResults 152 sObject 344 standard 278 StandardController 492 StandardSetController 495 static 112 StaticResourceCalloutMock 420 string 300 system 421 test 432 time 323 Type 438 URL 442 user-defined 107 userInfo 445 using with classes 107 Methods (continued) Version 447 void with side effects 107 XML Reader 526 XmlStreamWriter 531 MultiStaticResourceCalloutMock methods 414 testing callouts 516 N Namespace precedence 142 prefixes 141 type resolution 143 Nested lists 33 Network methods 561 New features in this release 12 new trigger variable 80 newMap trigger variable 80 Not In clause.Index Methods (continued) DMLOptions 386 double 295 enum 339 error object 389 exception 449 field describe results 353 field set describe results 361 Flow. 461 sendEmailMessage 461 set 38. 331 matcher 503 math 409 message 484 MultiStaticResourceCalloutMock 414 namespace prefixes and 142 Network 561 PageReference 485 passing-by-value 107 pattern 501 QueryLocator 385 recursive 107 reserveMassEmailCapacity 461 reserveSingleEmailCapacity 461 RestContext 415 RestRequest 415 RestResponse 418 schema 340 search 420 SelectOption 490 sendEmail 452. SOQL query 71 O Object lists 34 Objects ApexTestQueueItem 625 ApexTestResult 626 old trigger variable 80 oldMap trigger variable 80 Onramping 7 Opaque bounds 500 Operations DML 257 DML exceptions 278 Operators precedence 56 understanding 50 Order of trigger execution 87 Overloading custom API calls 229 P Packages creating 569. 591 post install script 569. Plugin interface data type conversions 585 Process. methods 107 Precedence. 270 Schedulable interface 93 Schedule Apex 93 Scheduler best practices 98 schedulable interface 93 testing 94 Schema methods 340 Search methods 420 Security and custom API calls 227. accessing fields through 31 Release notes 12 Remote site settings 241 RemoteAction annotation 132 Requests 74 Reserved keywords 614 REST Web Services Apex REST code samples 237 Apex REST introduction 231 Apex REST methods 231 exposing Apex classes 230 RestContext methods 415 RestRequest methods 415 RestResource annotation 133 RestResponse methods 418 retrieveCode call 599 Role hierarchy 186 rollback method 74 Rounding modes 293 RowCause field values 187 runAs method package versions 224 using 150. 111 S Salesforce. triggers and bulk 79 ProcessRequest class 540 ProcessResult class 541 ProcessSubmitRequest class 541 ProcessWorkitemRequest class 542 Production organizations. deploying Apex 594 Programming patterns triggers 92 Properties 115 Protected access modifier 103. 582 Process. 236 Person account triggers 89 Polymorphic relationships 70 Polymorphic.InputParameter class 579–580.PluginDescribeResult. 236 certificates 252 class 139 code 616 formulas 618 Q Queries execution limits 214 SOQL and SOSL 64 SOQL and SOSL expressions 49 working with results 65 Quick start 12 Quickstart tutorial understanding 18 R ReadOnly annotation 131 Reason field values 187 Recalculating sharing 193 Record ownership 186 Recovered records 87 Recursive methods 107 669 .PluginDescribeResult class 579–580.PluginResult class 582 Processing. 582 Process.PluginResult class 582 Sample implementation for lead conversion 585 Process. 224 runTests call 155.com version 144 Sample application code 605 data model 602 overview 602 tutorial 602 Sandbox organizations. deploying Apex 594 SaveResult object 264. 582 Process. 635 582 Process.Index Passing-by-value 107 Pattern class example 500 understanding 498 using 498 Pattern methods 501 Permissions enforcing using describe methods 140 Permissions and custom API calls 227. 111 Public access modifier 103.PluginDescribeResult.PluginDescribeResult.OutputParameter class 579–580. Recursive (continued) triggers 78 Regions and regular expressions 499 Regular expressions bounds 500 grouping 503 regions 499 searching 503 splitting 501 understanding 498 Relationships. 582 Process.PluginDescribeRequest class 579–580. 582 Process. 111 Process.PluginRequest class 581 Process.OutputParameter class 579–580. operator 56 Primitive data types passed by value 26 Private access modifier 103.InputParameter class 579–580.PluginDescribeResult.PluginRequest class 581 Process. locking rows for 73 large result lists 67 limit methods 406 locking 74 null values 69 parent-child relationship 70 Polymorphic relationships 70 preventing injection 172 querying all records 73 understanding 64 working with results 65 Sorting lists 35 SOSL injection 173 SOSL queries Apex variables in 71 dynamic 172 execution limits 214 expressions 49 limit methods 406 preventing injection 173 testing 152 understanding 64 working with results 65 Special characters 26 SSL authentication 252 Standard methods understanding 278 StandardController example 494 methods 492 StandardController class instantiation 492 understanding 492 StandardSetController example 496 methods 495 StandardSetController class instantiation 494 prototype object 494 understanding 494 Start and stop test 151 Statements assignment 57 execution limits 214 if-else 58 locking 73 method invoking 107 see also Exceptions 75 Static initialization code 112.Index Security (continued) Visualforce 618 SelectOption class 490 example 491 instantiation 490 methods 490 Set accessors 115 setFixedSearchResults method 152 Sets iterating 44 iteration for loops 61 methods 335 understanding 38 setSavepoint method 74 Severity. 601 compileClasses 601 compileTriggers 601 custom 227 executeAnonymous 98 retrieveCode 599 runTests 155 transaction control 74 when to use 11 SOAP API objects ApexTestQueueItem 154 ApexTestResult 154 sObjects access all 166 accessing fields through relationships 31 data types 26. 114 methods 112 variables 112 670 . 74 foreign key 70 inline. 29 dereferencing fields 65 describe result methods 349 describe results 164 expressions 56 fields 30 formula fields 65 lists 34 methods 344 sorting 35 that cannot be used together 276 that do not support DML operations 275 tokens 164 validating 32 SOQL injection 172 SOQL queries aggregate functions 66 Apex variables in 71 dynamic 172 execution limits 214 expressions 49 for loops 62. messages 484 Sharing access levels 188 and custom API calls 227. 236 Apex managed 186 reason field values 187 recalculating 193 rules 186 understanding 186 Sharing reasons database object 385 recalculating 193 understanding 188 Site class 554 size trigger variable 80 SOAP and overloading 229 SOAP API calls compileAndTest 596. using 83 merge events and 86 recovered records 87 syntax 79 transaction control 74 transaction control statements 79 undelete 87 understanding 78 unique fields 84 Try-catch-finally statements 75 Tutorial 12. Apex 107 UserInfo methods 445 671 .Index StaticResourceCalloutMock methods 420 testing callouts 516 Strings data type 26 methods 300 super keyword 121 Syntax case sensitivity 48 comments 57 variables 47 System architecture. deploying Apex 594 Update database method 269 Update statement 269 Upsert database method 271 Upsert statement 271 UpsertResult object 273 URL methods 442 User managed sharing 186 User-defined methods. 23 Trigger-ignoring operations 89 U Uncaught exception handling 213 Undelete database method 267 Undelete statement 267 Undelete triggers 87 UndeleteResult object 268 UninstallHandler interface onUninstall method 591 Unit tests for SOSL queries 152 running 153 understanding 148 Unlimited Edition. Apex 3 System Log console using 203 System methods namespace prefixes 142 static 421 System namespace prefix 142 System validation 87 Triggers API version 144 bulk exception handling 278 bulk processing 79 bulk queries 83–84 common idioms 83 context variable considerations 82 context variables 80 defining 84 design pattern 92 entity and field considerations 90 events 79 exceptions 91 execution order 87 ignored operations 89 isValid flag 84 maps and sets. 224 using start and stop test 151 what to test 147 testMethod keyword 148 Tests data access 149 for SOSL queries 152 isTest annotation 128 running 153 understanding 146–147 this keyword 122 Throw statements 75 Time data type 26 methods 323 TimeZone class 437 Tokens fields 165 reserved 614 sObjects 164 Tools 596 Traditional for loops 61 Transaction control statements triggers and 79 understanding 74 transient keyword 123 Transparent bounds 500 Trigger step by step walkthrough 18–21. 516 example 157 governor limits 151 runAs 150. 602 Type methods 438 Type resolution 143 Types Primitive 26 sObject 29 understanding 26 Typographical conventions 12 T Test methods 432 Test methods Visualforce 432 Testing best practices 156 callouts 514. system 87 Variables access modifiers 111 declaring 47 in SOQL and SOSL queries 71 instance 112–113 local 112 precedence 142 static 112 trigger context 80 using with classes 106 Version Methods 447 Version settings API version 144 package versions 145 understanding 143 Very large SOQL queries 67 Virtual definition modifier 103 Visualforce ApexPages methods 373 message severity 484 pages 471 security tips 616 when to use 11 Web services API calls (continued) compileClasses 633 compileTriggers 634 executeanonymous 634 runTests 635 WebService methods considerations 227 exposing data 227 overloading 229 understanding 227 WebServiceMock Interface doInvoke method 593 Where clause.Index V Validating sObject and field names 32 Validation. methods 531 672 . methods 526 XmlStreamWriter class. SOQL query 71 While loops 60 with sharing keywords 124 without sharing keywords 124 Workflow 87 Writing Apex 4 WSDLs creating an Apex class from 241 debugging 251 example 246 generating 227 mapping headers 250 overloading 229 runtime events 251 testing 248 W Walk-through. sample application 602 Web services API calls available for Apex 624 compileAndTest 629 X XML reader methods 526 XML writer methods 531 XmlNode class 535 XmlStreamReader class.