- Загрузить через REST >
- Загрузка через SOAP
- Загрузка через предопределенную/созданную библиотеку артефактов Maven
Ни одна из моих реальных попыток пока не сработала, и мой вопрос, очевидно, как заставить его работать или в чем моя ошибка.
Я пробовал следующее:
- Загрузить через API метаданных createMetadata()
developer.salesforce.com: Руководство разработчика API метаданных | Разработка метаданных на основе CRUD
- developer.salesforce.com API инструментов | Ресурсы REST
Подход API метаданных
Я начал с подхода API метаданных:
@Test
void testTriggerUploadMetadataApi() {
String username = "REDACTED";
String password = "REDACTED";
String securityToken = "REDACTED";
String url = "https://REDACTEDDOMAIN.my.salesforce.com/services/Soap";
String authPrefix = "/u";
String servicePrefix = "/m";
String version = "/60.0";
LoginResponse loginResponse = this.authController
.authLoginPost(new Login("REDACTED", "REDACTED").thirdPartyConfig(thirdPartyConfig))
.block();
assertNotNull(loginResponse);
// Session is here a wrapper for the actual REST API OAuth Token with additional metadata
Session session =
assertDoesNotThrow(() -> new ObjectMapper().readValue(loginResponse.getToken(), Session.class));
ConnectorConfig connectorConfig = new ConnectorConfig();
connectorConfig.setUsername(username);
connectorConfig.setPassword(password + securityToken);
connectorConfig.setAuthEndpoint("https://login.salesforce.com/service/Soap" + authPrefix + version);
connectorConfig.setServiceEndpoint(url + servicePrefix + version);
connectorConfig.setProxy("REDACTED", 8080);
Transport transport = new JdkHttpTransport(connectorConfig);
connectorConfig.setTransport(transport.getClass());
MetadataConnection metadataConnection = assertDoesNotThrow(() -> new MetadataConnection(connectorConfig));
metadataConnection.setSessionHeader(session.getBearerTokenString());
ApexTrigger apexTrigger = new ApexTrigger();
apexTrigger.setFullName("SomeTrigger");
apexTrigger.setStatus(ApexCodeUnitStatus.Active);
apexTrigger.setApiVersion(56.0);
apexTrigger.setContent(
"trigger SomeTrigger on Account(after insert, after update {}".getBytes(StandardCharsets.UTF_8));
assertDoesNotThrow(() -> metadataConnection.upsertMetadata(new Metadata[] {apexTrigger}));
}
В результате:
org.opentest4j.AssertionFailedError: Unexpected exception thrown: com.sforce.ws.SoapFaultException: INVALID_TYPE: This type of object is not available for this organization
at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:152)
at org.junit.jupiter.api.AssertDoesNotThrow.createAssertionFailedError(AssertDoesNotThrow.java:84)
at org.junit.jupiter.api.AssertDoesNotThrow.assertDoesNotThrow(AssertDoesNotThrow.java:75)
at org.junit.jupiter.api.AssertDoesNotThrow.assertDoesNotThrow(AssertDoesNotThrow.java:58)
at org.junit.jupiter.api.Assertions.assertDoesNotThrow(Assertions.java:3228)
at redacted.package.name.SFLoginTest.testTriggerUploadMetadataApi(SFLoginTest.java:139)
Затем я начал немного исследовать и нашел следующую ветку-новатора, где в комментариях Дэниел Баллинджер из Salesforce утверждает, что это, вероятно, невозможно, поскольку "Это тип метаданных не поддерживается вызовами create(), delete() и update().
Хотя это не является явным, это также относится к методу createMetadata(), для которого функция create() была устаревшей."
Он также утверждает, что «Вместо этого вы можете использовать метод развертывания API метаданных или API инструментов для создания класса Apex»., так что я продолжил исследование где я нашел эту ветку-новатора, где Сунад Расане заявляет, что вместо этого он использовал Tooling API со ссылкой на эту ветку обмена стеками, где приведен пример загрузки триггера через Tooling API уже присутствовал, поэтому я решил использовать Tooling API, поскольку он выглядел удобным в использовании:
Подход Tooling API
@Test
void testTriggerUploadToolingApi() {
Map thirdPartyConfig = getThirdPartyConfig();
LoginResponse loginResponse = this.authController
.authLoginPost(new Login("REDACTED", "REDACTED").thirdPartyConfig(thirdPartyConfig))
.block();
assertNotNull(loginResponse);
// Session is here a wrapper for the actual REST API OAuth Token with additional metadata
Session session =
assertDoesNotThrow(() -> new ObjectMapper().readValue(loginResponse.getToken(), Session.class));
String url = session.getBaseUrl() + "/services/data/" + session.getApiVersion() + "/sobjects/ApexTrigger";
System.out.println("Request URL: [" + url + "]");
Map apexTrigger = new LinkedHashMap();
apexTrigger.put("Name", "UploadTest_AccountTrigger");
apexTrigger.put("TableEnumOrId", "Account");
apexTrigger.put(
"Body",
assertDoesNotThrow(() -> Files.readString(
Path.of("src/test/resources/salesforce/apex/SimpleAccountTriggerExpected.txt"))));
String requestBody = assertDoesNotThrow(() -> new ObjectMapper().writeValueAsString(apexTrigger));
System.out.println("Request body: [" + requestBody + "]");
HttpClient httpClient = HttpClient.newBuilder()
.proxy(ProxySelector.of(new InetSocketAddress("REDACTED", 8080)))
.connectTimeout(Duration.of(60, ChronoUnit.SECONDS))
.build();
HttpRequest uploadRequest = HttpRequest.newBuilder()
.uri(URI.create(url))
.timeout(Duration.of(60, ChronoUnit.SECONDS))
.POST(HttpRequest.BodyPublishers.ofString(requestBody, StandardCharsets.UTF_8))
.header("Authorization", "OAuth " + session.getBearerTokenString())
.header("Content-Type", "application/json")
.build();
HttpResponse response =
assertDoesNotThrow(() -> httpClient.send(uploadRequest, HttpResponse.BodyHandlers.ofString()));
System.out.println("Status Code: [" + response.statusCode()+ "]");
System.out.println("Body: [" + response.body() + "]");
assertTrue(String.valueOf(response.statusCode()).startsWith("2"));
}
В результате:
Expected :true
Actual :false
org.opentest4j.AssertionFailedError: expected: but was:
at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
at org.junit.jupiter.api.AssertTrue.failNotTrue(AssertTrue.java:63)
at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:36)
at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:31)
at org.junit.jupiter.api.Assertions.assertTrue(Assertions.java:183)
at redacted.package.nameSFLoginTest.testTriggerUploadToolingApi(SFLoginTest.java:83)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at io.micronaut.test.extensions.junit5.MicronautJunit5Extension$2.proceed(MicronautJunit5Extension.java:142)
at io.micronaut.test.extensions.AbstractMicronautExtension.interceptEach(AbstractMicronautExtension.java:157)
at io.micronaut.test.extensions.AbstractMicronautExtension.interceptTest(AbstractMicronautExtension.java:114)
at io.micronaut.test.extensions.junit5.MicronautJunit5Extension.interceptTestMethod(MicronautJunit5Extension.java:129)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
Со следующим выводом на STDOUT:
Request URL: [https://REDACTEDDOMAIN.my.salesforce.co ... pexTrigger]
Request body: [{"Name":"UploadTest_AccountTrigger","TableEnumOrId":"Account","Body":"trigger Account_AccountWebhook on Account (after insert, after update) {}"}]
Status Code: [404]
Body: [[{"errorCode":"NOT_FOUND","message":"The requested resource does not exist"}]]
Подробнее здесь: https://stackoverflow.com/questions/781 ... r-via-java