It's fairly easy to create an ApexClass in the SOAP Tooling API:
ConnectorConfig partnerConfig = new ConnectorConfig();
partnerConfig.setManualLogin(true);
PartnerConnection partnerConnection = com.sforce.soap.partner.Connector.newConnection(partnerConfig);
LoginResult lr = partnerConnection.login(<username>, <password> + <security_token>);
ConnectorConfig toolingConfig = new ConnectorConfig();
toolingConfig.setSessionId(lr.getSessionId());
toolingConfig.setServiceEndpoint(lr.getServerUrl().replace('u', 'T'));
toolingConnection = com.sforce.soap.tooling.Connector.newConnection(toolingConfig);
try
{
String classBody = "public class Messages {\n"
+ "public string SayHello() {\n"
+ " return 'Hello';\n" + "}\n"
+ "}";
ApexClass apexClass = new ApexClass();
apexClass.setBody(classBody);
ApexClass[] classes = {apexClass};
classId = null;
SaveResult[] saveResults = toolingConnection.create(classes);
if (saveResults[0].isSuccess())
{
System.out.println("Successfully created Class: " + saveResults[0].getId());
classId = saveResults[0].getId();
}
else
{
System.out.println("Error: could not create Class ");
System.out.println("The error reported was: " + saveResults[0].getErrors()[0].getMessage() + "\n");
throw new Exception("Error");
}
}
catch(Exception e)
{
//Handle exception
}
This immediately creates the class in your org. However, I would like to be able to utilize the MetadataContainer functionality to create classes in this manner:
ConnectorConfig partnerConfig = new ConnectorConfig();
partnerConfig.setManualLogin(true);
PartnerConnection partnerConnection = com.sforce.soap.partner.Connector.newConnection(partnerConfig);
LoginResult lr = partnerConnection.login(<username>, <password> + <security_token>);
ConnectorConfig toolingConfig = new ConnectorConfig();
toolingConfig.setSessionId(lr.getSessionId());
toolingConfig.setServiceEndpoint(lr.getServerUrl().replace('u', 'T'));
toolingConnection = com.sforce.soap.tooling.Connector.newConnection(toolingConfig);
try
{
MetadataContainer Container = new MetadataContainer();
Container.setName("SampleContainer2");
MetadataContainer[] Containers = { Container };
SaveResult[] containerResults = toolingConnection.create(Containers);
if (containerResults[0].isSuccess())
{
System.out.println("Successfully created MetadataContainer: " + containerResults[0].getId());
containerId = containerResults[0].getId();
}
else
{
System.out.println("Error: could not create MetadataContainer ");
System.out.println("The error reported was: " + containerResults[0].getErrors()[0].getMessage() + "\n");
throw new Exception("Error");
}
String classBody = "public class Messages {\n"
+ "public string SayHello() {\n"
+ " return 'Hello';\n" + "}\n"
+ "}";
ApexClassMember createClassMember = new ApexClassMember();
createClassMember.setFullName("Messages");
createClassMember.setBody(classBody);
createClassMember.setMetadataContainerId(containerId);
ApexClassMember[] createClassMembers = { createClassMember };
SaveResult[] createResults = toolingConnection.create(createClassMembers);
if (createResults[0].isSuccess())
{
System.out.println("Successfully created class in metadata container: " + createResults[0].getId());
}
else
{
System.out.println("Error: could not create Class Member in metadata container");
System.out.println("The error reported was: " + createResults[0].getErrors()[0].getMessage() + "\n");
throw new Exception("Error");
}
}
catch(Exception e)
{
//Handle exception
}
When I try this, I get an error as follows:
Error: could not create Class Member in metadata container
The error reported was: Required fields are missing: [Content]
Adding a line to populate the Content field on ApexClassMetadata only results in a different error:
The error reported was: Unable to create/update fields: Content. Please check the security settings of this field and verify that it is read/write for your profile or permission set.
My question, therefore: is it possible to create classes using MetatadataContainers instead of just updating them? Salesforce's own documentation isn't clear on this matter, which is why I've come here.