Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/main/java/com/crowdin/client/branches/BranchesApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public ResponseObject<DeleteJobStatus> checkBranchDeletionStatus(Long projectId,
* @return clone status
* @see <ul>
* <li><a href="https://developer.crowdin.com/api/v2/string-based/#operation/api.projects.branches.clones.post" target="_blank"><b>API Documentation</b></a></li>
* <li><a href="https://developer.crowdin.com/enterprise/api/v2/string-based/#operation/api.projects.branches.clones.post" target="_blank"><b>Enterprise API Documentation</b></a></li>
* </ul>
*/
public ResponseObject<BranchCloneStatus> cloneBranch(Long projectId, Long branchId, CloneBranchRequest request) throws HttpException, HttpBadRequestException {
Expand All @@ -100,6 +101,7 @@ public ResponseObject<BranchCloneStatus> cloneBranch(Long projectId, Long branch
* @return clone status
* @see <ul>
* <li><a href="https://developer.crowdin.com/api/v2/string-based/#operation/api.projects.branches.clones.get" target="_blank"><b>API Documentation</b></a></li>
* <li><a href="https://developer.crowdin.com/enterprise/api/v2/string-based/#operation/api.projects.branches.clones.get" target="_blank"><b>Enterprise API Documentation</b></a></li>
* </ul>
*/
public ResponseObject<BranchCloneStatus> checkCloneBranchStatus(Long projectId, Long branchId, String cloneId) throws HttpException, HttpBadRequestException {
Expand All @@ -114,6 +116,7 @@ public ResponseObject<BranchCloneStatus> checkCloneBranchStatus(Long projectId,
* @return cloned branch
* @see <ul>
* <li><a href="https://developer.crowdin.com/api/v2/string-based/#operation/api.projects.branches.clones.branch.get" target="_blank"><b>API Documentation</b></a></li>
* <li><a href="https://developer.crowdin.com/enterprise/api/v2/string-based/#operation/api.projects.branches.clones.branch.get" target="_blank"><b>Enterprise API Documentation</b></a></li>
* </ul>
*/
public ResponseObject<ClonedBranch> getClonedBranch(Long projectId, Long branchId, String cloneId) throws HttpException, HttpBadRequestException {
Expand All @@ -128,6 +131,7 @@ public ResponseObject<ClonedBranch> getClonedBranch(Long projectId, Long branchI
* @return merge status
* @see <ul>
* <li><a href="https://developer.crowdin.com/api/v2/string-based/#operation/api.projects.branches.merges.post" target="_blank"><b>API Documentation</b></a></li>
* <li><a href="https://developer.crowdin.com/enterprise/api/v2/string-based/#operation/api.projects.branches.merges.post" target="_blank"><b>Enterprise API Documentation</b></a></li>
* </ul>
*/
public ResponseObject<BranchMergeStatus> mergeBranch(Long projectId, Long branchId, MergeBranchRequest request) throws HttpException, HttpBadRequestException {
Expand All @@ -141,7 +145,8 @@ public ResponseObject<BranchMergeStatus> mergeBranch(Long projectId, Long branch
* @param mergeId merge identifier
* @return merge status
* @see <ul>
* <li><a href="https://developer.crowdin.com/api/v2/string-based/#operation/api.projects.branches.clones.get" target="_blank"><b>API Documentation</b></a></li>
* <li><a href="https://developer.crowdin.com/api/v2/string-based/#operation/api.projects.branches.merges.get" target="_blank"><b>API Documentation</b></a></li>
* <li><a href="https://developer.crowdin.com/enterprise/api/v2/string-based/#operation/api.projects.branches.merges.get" target="_blank"><b>Enterprise API Documentation</b></a></li>
* </ul>
*/
public ResponseObject<BranchMergeStatus> checkMergeBranchStatus(Long projectId, Long branchId, String mergeId) throws HttpException, HttpBadRequestException {
Expand All @@ -156,6 +161,7 @@ public ResponseObject<BranchMergeStatus> checkMergeBranchStatus(Long projectId,
* @return merge summary
* @see <ul>
* <li><a href="https://developer.crowdin.com/api/v2/string-based/#operation/api.projects.branches.merges.summary.get" target="_blank"><b>API Documentation</b></a></li>
* <li><a href="https://developer.crowdin.com/enterprise/api/v2/string-based/#operation/api.projects.branches.merges.summary.get" target="_blank"><b>Enterprise API Documentation</b></a></li>
* </ul>
*/
public ResponseObject<BranchMergeSummary> getMergeBranchSummary(Long projectId, Long branchId, String mergeId) throws HttpException, HttpBadRequestException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ public static class Attributes {
private Integer sourceBranchId;
private Boolean deleteAfterMerge;
private Boolean acceptSourceChanges;
private Boolean dryRun;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ public class BranchMergeSummary {
private Long sourceBranchId;
private Long targetBranchId;
private Boolean dryRun;
private Boolean acceptSourceChanges;
private Map<String, Long> details;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ public class CloneBranchRequest {

private String name;
private String title;
private Boolean isProtected;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public class ClonedBranch {
private Long projectId;
private String name;
private String title;
private Boolean isProtected;
private Date createdAt;
private Date updatedAt;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import lombok.SneakyThrows;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

public class EnumDeserializer extends JsonDeserializer<Enum> implements ContextualDeserializer {

Expand Down Expand Up @@ -40,12 +41,25 @@ public Enum deserialize(JsonParser p, DeserializationContext ctxt) throws IOExce
}


/**
* Values unknown to the SDK (e.g. added to the API after this SDK version was released)
* are deserialized as {@code null} instead of failing the whole response.
*/
@SneakyThrows
private Enum deserialize(Class<? extends Enum> type, String value) {
if (EnumConverter.class.isAssignableFrom(type)) {
return (Enum) type.getMethod("from", String.class).invoke(null, value);
} else {
return Enum.valueOf(type, value);
try {
if (EnumConverter.class.isAssignableFrom(type)) {
return (Enum) type.getMethod("from", String.class).invoke(null, value);
} else {
return Enum.valueOf(type, value);
}
} catch (InvocationTargetException e) {
if (e.getCause() instanceof IllegalArgumentException) {
return null;
}
throw e;
} catch (IllegalArgumentException e) {
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package com.crowdin.client.core.http.impl.json;

import com.crowdin.client.sourcefiles.model.DocxFileExportOptions;
import com.crowdin.client.sourcefiles.model.ExportOptions;
import com.crowdin.client.sourcefiles.model.GeneralFileExportOptions;
import com.crowdin.client.sourcefiles.model.JavaScriptFileExportOptions;
import com.crowdin.client.sourcefiles.model.MdFileExportOptions;
import com.crowdin.client.sourcefiles.model.MdxV1FileExportOptions;
import com.crowdin.client.sourcefiles.model.MdxV2FileExportOptions;
import com.crowdin.client.sourcefiles.model.PropertyFileExportOptions;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
Expand All @@ -16,6 +20,15 @@
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import static com.crowdin.client.core.http.impl.json.FileInfoDeserializer.containsAny;

/**
* Resolves the concrete {@link ExportOptions} class.
* <p>
* Property and JavaScript options are resolved by their keys as before. All other options resolve to
* {@link GeneralFileExportOptions} or one of its format-specific subclasses, chosen by the parent file {@code type}
* (when known) or by format-specific keys.
*/
public class FileExportOptionsDeserializer extends JsonDeserializer<ExportOptions> {

private final ObjectMapper objectMapper;
Expand All @@ -36,7 +49,39 @@ public ExportOptions deserialize(JsonParser p, DeserializationContext ctxt) thro
} else if (fields.contains("exportQuotes")) {
return this.objectMapper.readValue(treeNode.toString(), JavaScriptFileExportOptions.class);
} else {
return this.objectMapper.readValue(treeNode.toString(), GeneralFileExportOptions.class);
Class<? extends GeneralFileExportOptions> clazz = resolveByFileType(FileInfoDeserializer.getFileType(ctxt));
if (clazz == null) {
clazz = resolveByFields(fields);
}
return this.objectMapper.readValue(treeNode.toString(), clazz);
}
}

private static Class<? extends GeneralFileExportOptions> resolveByFileType(String fileType) {
if (fileType == null) {
return null;
}
switch (fileType) {
case "md":
return MdFileExportOptions.class;
case "mdx_v1":
return MdxV1FileExportOptions.class;
case "mdx_v2":
return MdxV2FileExportOptions.class;
case "docx":
return DocxFileExportOptions.class;
default:
return null;
}
}

private static Class<? extends GeneralFileExportOptions> resolveByFields(List<String> fields) {
if (containsAny(fields, "allowWordStyleOptimization", "translateExcelExcludeColors")) {
return DocxFileExportOptions.class;
} else if (containsAny(fields, "strongMarker", "emphasisMarker", "unorderedListBullet", "tableColumnWidth", "frontMatterQuotes")) {
return MdFileExportOptions.class;
} else {
return GeneralFileExportOptions.class;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
package com.crowdin.client.core.http.impl.json;

import com.crowdin.client.sourcefiles.model.AdocFileImportOptions;
import com.crowdin.client.sourcefiles.model.DocxFileImportOptions;
import com.crowdin.client.sourcefiles.model.HtmlFileImportOptions;
import com.crowdin.client.sourcefiles.model.HtmlWithFrontMatterFileImportOptions;
import com.crowdin.client.sourcefiles.model.IdmlFileImportOptions;
import com.crowdin.client.sourcefiles.model.ImportOptions;
import com.crowdin.client.sourcefiles.model.MdFileImportOptions;
import com.crowdin.client.sourcefiles.model.MdxV1FileImportOptions;
import com.crowdin.client.sourcefiles.model.MdxV2FileImportOptions;
import com.crowdin.client.sourcefiles.model.OtherFileImportOptions;
import com.crowdin.client.sourcefiles.model.SpreadsheetFileImportOptions;
import com.crowdin.client.sourcefiles.model.StringCatalogFileImportOptions;
import com.crowdin.client.sourcefiles.model.VdfFileImportOptions;
import com.crowdin.client.sourcefiles.model.WebXmlFileImportOptions;
import com.crowdin.client.sourcefiles.model.XmlFileImportOptions;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
Expand All @@ -17,6 +27,15 @@
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import static com.crowdin.client.core.http.impl.json.FileInfoDeserializer.containsAny;

/**
* Resolves the concrete {@link ImportOptions} class.
* <p>
* Options with Docx, Spreadsheet or Xml specific keys are resolved as before. All other options resolve to
* {@link OtherFileImportOptions} or one of its format-specific subclasses, chosen by the parent file {@code type}
* (when known) or by format-specific keys.
*/
public class FileImportOptionsDeserializer extends JsonDeserializer<ImportOptions> {

private final ObjectMapper objectMapper;
Expand All @@ -39,7 +58,61 @@ public ImportOptions deserialize(JsonParser p, DeserializationContext ctxt) thro
} else if (fields.contains("translateContent")) {
return this.objectMapper.readValue(treeNode.toString(), XmlFileImportOptions.class);
} else {
return this.objectMapper.readValue(treeNode.toString(), OtherFileImportOptions.class);
Class<? extends OtherFileImportOptions> clazz = resolveByFileType(FileInfoDeserializer.getFileType(ctxt));
if (clazz == null) {
clazz = resolveByFields(fields);
}
return this.objectMapper.readValue(treeNode.toString(), clazz);
}
}

private static Class<? extends OtherFileImportOptions> resolveByFileType(String fileType) {
if (fileType == null) {
return null;
}
switch (fileType) {
case "html":
return HtmlFileImportOptions.class;
case "fm_html":
return HtmlWithFrontMatterFileImportOptions.class;
case "md":
return MdFileImportOptions.class;
case "mdx_v1":
return MdxV1FileImportOptions.class;
case "mdx_v2":
return MdxV2FileImportOptions.class;
case "webxml":
return WebXmlFileImportOptions.class;
case "idml":
return IdmlFileImportOptions.class;
case "adoc":
return AdocFileImportOptions.class;
case "vdf":
return VdfFileImportOptions.class;
default:
return null;
}
}

private static Class<? extends OtherFileImportOptions> resolveByFields(List<String> fields) {
if (fields.contains("excludedElements")) {
return fields.contains("excludedFrontMatterElements")
? HtmlWithFrontMatterFileImportOptions.class
: HtmlFileImportOptions.class;
} else if (containsAny(fields, "excludeCodeBlocks", "excludedFrontMatterElements")) {
return MdFileImportOptions.class;
} else if (containsAny(fields, "hideAttributeValues", "inlineTags")) {
return HtmlFileImportOptions.class;
} else if (fields.contains("inlineHyperlinkText")) {
return IdmlFileImportOptions.class;
} else if (fields.contains("importKeyAsSource")) {
return StringCatalogFileImportOptions.class;
} else if (fields.contains("excludeIncludeDirectives")) {
return AdocFileImportOptions.class;
} else if (containsAny(fields, "convertIcu", "addGenderArgument")) {
return VdfFileImportOptions.class;
} else {
return OtherFileImportOptions.class;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;

import java.io.IOException;
import java.util.List;
Expand All @@ -16,6 +18,12 @@

public class FileInfoDeserializer extends JsonDeserializer<FileInfo> {

/**
* Deserialization context attribute holding the {@code type} of the file whose import/export options are being
* deserialized. Used by {@link FileImportOptionsDeserializer} and {@link FileExportOptionsDeserializer}.
*/
public static final String FILE_TYPE_ATTRIBUTE = "crowdin.sourcefiles.fileType";

private final ObjectMapper objectMapper;

public FileInfoDeserializer(ObjectMapper objectMapper) {
Expand All @@ -30,13 +38,31 @@ public FileInfo deserialize(JsonParser p, DeserializationContext ctxt) throws IO
.stream(iterable.spliterator(), false)
.collect(Collectors.toList());
if (containsAny(fields, "revisionId", "parserVersion", "priority", "importOptions", "exportOptions", "excludedTargetLanguages", "createdAt", "updatedAt")) {
return this.objectMapper.readValue(treeNode.toString(), File.class);
ObjectReader reader = this.objectMapper.readerFor(File.class);
String fileType = getFileType(treeNode);
if (fileType != null) {
reader = reader.withAttribute(FILE_TYPE_ATTRIBUTE, fileType);
}
return reader.readValue(treeNode.toString());
} else {
return this.objectMapper.readValue(treeNode.toString(), FileInfo.class);
}
}

private static boolean containsAny(List<String> fields, String... values) {
private static String getFileType(TreeNode treeNode) {
TreeNode typeNode = treeNode.get("type");
if (typeNode instanceof JsonNode && ((JsonNode) typeNode).isTextual()) {
return ((JsonNode) typeNode).asText();
}
return null;
}

static String getFileType(DeserializationContext ctxt) {
Object fileType = ctxt.getAttribute(FILE_TYPE_ATTRIBUTE);
return fileType instanceof String ? (String) fileType : null;
}

static boolean containsAny(List<String> fields, String... values) {
for (String value : values) {
if (fields.contains(value)) {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ public JacksonJsonTransformer() {
SimpleModule enumModule = new SimpleModule()
.addDeserializer(Enum.class, new EnumDeserializer());

ObjectMapper fileOptionsObjectMapper = cleanObjectMapper.copy()
.registerModule(enumModule);

SimpleModule module = new SimpleModule()
.addDeserializer(Date.class, new DateDeserializer())
.addSerializer(Enum.class, new EnumSerializer())
Expand All @@ -43,8 +46,8 @@ public JacksonJsonTransformer() {
.addDeserializer(FileInfo.class, new FileInfoDeserializer(cleanObjectMapper.copy()
.registerModule(enumModule)
.registerModule(new SimpleModule()
.addDeserializer(ImportOptions.class, new FileImportOptionsDeserializer(cleanObjectMapper))
.addDeserializer(ExportOptions.class, new FileExportOptionsDeserializer(cleanObjectMapper)))))
.addDeserializer(ImportOptions.class, new FileImportOptionsDeserializer(fileOptionsObjectMapper))
.addDeserializer(ExportOptions.class, new FileExportOptionsDeserializer(fileOptionsObjectMapper)))))
.addDeserializer(LanguageTranslations.class, new LanguageTranslationsDeserializer(cleanObjectMapper))
.addDeserializer(FileFormatSettingsResource.class, new FileFormatSettingsDeserializer(cleanObjectMapper))
.addDeserializer(StringsExporterSettingsResource.class, new StringsExporterSettingsDeserializer(cleanObjectMapper));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ public class AddBranchRequest {
private String title;
private String exportPattern;
private Priority priority;
/**
* String-based projects only
*/
private Boolean isProtected;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import lombok.Data;

import java.util.List;
import java.util.Map;

@Data
public class AddFileRequest {
Expand All @@ -19,4 +20,8 @@ public class AddFileRequest {
private ExportOptions exportOptions;
private List<String> excludedTargetLanguages;
private List<Long> attachLabelIds;
/**
* Custom fields (Enterprise only)
*/
private Map<String, Object> fields;
}
Loading
Loading