Decrease complexity when using Protobuf builders

This commit is contained in:
Simon Brandhof 2016-11-11 14:44:36 +01:00
parent a10e9e92d4
commit 5f19514f1f
14 changed files with 101 additions and 118 deletions

View File

@ -30,6 +30,7 @@ import org.sonar.scanner.protocol.input.ProjectRepositories;
import org.sonarqube.ws.WsBatch.WsProjectResponse;
import org.sonarqube.ws.WsBatch.WsProjectResponse.FileData.Builder;
import static org.sonar.core.util.Protobuf.setNullable;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
@ -85,7 +86,7 @@ public class ProjectAction implements BatchWsAction {
private static WsProjectResponse buildResponse(ProjectRepositories data) {
WsProjectResponse.Builder response = WsProjectResponse.newBuilder();
setLastAnalysisDate(response, data);
setNullable(data.lastAnalysisDate(), response::setLastAnalysisDate, Date::getTime);
response.setTimestamp(data.timestamp());
response.getMutableFileDataByModuleAndPath()
.putAll(buildFileDataByModuleAndPath(data));
@ -95,13 +96,6 @@ public class ProjectAction implements BatchWsAction {
return response.build();
}
private static void setLastAnalysisDate(WsProjectResponse.Builder response, ProjectRepositories data) {
Date lastAnalysisDate = data.lastAnalysisDate();
if (lastAnalysisDate != null) {
response.setLastAnalysisDate(lastAnalysisDate.getTime());
}
}
private static Map<String, WsProjectResponse.FileDataByPath> buildFileDataByModuleAndPath(ProjectRepositories data) {
Map<String, WsProjectResponse.FileDataByPath> fileDataByModuleAndPathResponse = new HashMap<>();
for (Map.Entry<String, Map<String, FileData>> moduleAndFileDataByPathEntry : data.fileDataByModuleAndPath().entrySet()) {
@ -150,13 +144,8 @@ public class ProjectAction implements BatchWsAction {
private static WsProjectResponse.FileData toFileDataResponse(FileData fileData) {
Builder fileDataBuilder = WsProjectResponse.FileData.newBuilder();
if (fileData.hash() != null) {
fileDataBuilder.setHash(fileData.hash());
}
if (fileData.revision() != null) {
fileDataBuilder.setRevision(fileData.revision());
}
setNullable(fileData.hash(), fileDataBuilder::setHash);
setNullable(fileData.revision(), fileDataBuilder::setRevision);
return fileDataBuilder.build();
}
}

View File

@ -24,7 +24,8 @@ import java.util.Map;
import org.sonar.db.component.ComponentDto;
import org.sonarqube.ws.WsComponents;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.base.Strings.emptyToNull;
import static org.sonar.core.util.Protobuf.setNullable;
class ComponentDtoToWsComponent {
private ComponentDtoToWsComponent() {
@ -37,16 +38,9 @@ class ComponentDtoToWsComponent {
.setKey(dto.key())
.setName(dto.name())
.setQualifier(dto.qualifier());
if (!isNullOrEmpty(dto.path())) {
wsComponent.setPath(dto.path());
}
if (!isNullOrEmpty(dto.description())) {
wsComponent.setDescription(dto.description());
}
if (!isNullOrEmpty(dto.language())) {
wsComponent.setLanguage(dto.language());
}
setNullable(emptyToNull(dto.path()), wsComponent::setPath);
setNullable(emptyToNull(dto.description()), wsComponent::setDescription);
setNullable(emptyToNull(dto.language()), wsComponent::setLanguage);
return wsComponent;
}

View File

@ -42,6 +42,7 @@ import org.sonarqube.ws.WsComponents.SearchWsResponse;
import org.sonarqube.ws.client.component.SearchWsRequest;
import static com.google.common.collect.FluentIterable.from;
import static org.sonar.core.util.Protobuf.setNullable;
import static org.sonar.server.ws.WsParameterBuilder.createQualifiersParameter;
import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
@ -164,10 +165,7 @@ public class SearchAction implements ComponentsWsAction {
.setKey(dto.key())
.setName(dto.name())
.setQualifier(dto.qualifier());
if (dto.language() != null) {
builder.setLanguage(dto.language());
}
setNullable(dto.language(), builder::setLanguage);
return builder.build();
}
}

View File

@ -213,7 +213,7 @@ public class SearchProjectsAction implements ComponentsWsAction {
.map(bucketToFacetValue)
.forEach(wsFacet::addValues);
} else {
wsFacet.addAllValues(Collections.<Common.FacetValue>emptyList());
wsFacet.addAllValues(Collections.emptyList());
}
return wsFacet.build();

View File

@ -49,7 +49,9 @@ import org.sonar.server.ws.WsResponseCommonFormat;
import org.sonarqube.ws.Common;
import org.sonarqube.ws.Issues;
import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.base.Strings.nullToEmpty;
import static org.sonar.core.util.Protobuf.setNullable;
public class SearchResponseFormat {
@ -141,10 +143,8 @@ public class SearchResponseFormat {
private void formatIssue(Issues.Issue.Builder issueBuilder, IssueDto dto, SearchResponseData data) {
issueBuilder.setKey(dto.getKey());
Common.RuleType type = Common.RuleType.valueOf(dto.getType());
if (type != null) {
issueBuilder.setType(type);
}
setNullable(dto.getType(), issueBuilder::setType, Common.RuleType::valueOf);
ComponentDto component = data.getComponentByUuid(dto.getComponentUuid());
issueBuilder.setComponent(component.key());
// Only used for the compatibility with the Java WS Client <= 4.4 used by Eclipse
@ -159,12 +159,8 @@ public class SearchResponseFormat {
}
issueBuilder.setRule(dto.getRuleKey().toString());
issueBuilder.setSeverity(Common.Severity.valueOf(dto.getSeverity()));
if (!Strings.isNullOrEmpty(dto.getAssignee())) {
issueBuilder.setAssignee(dto.getAssignee());
}
if (!Strings.isNullOrEmpty(dto.getResolution())) {
issueBuilder.setResolution(dto.getResolution());
}
setNullable(emptyToNull(dto.getAssignee()), issueBuilder::setAssignee);
setNullable(emptyToNull(dto.getResolution()), issueBuilder::setResolution);
issueBuilder.setStatus(dto.getStatus());
issueBuilder.setMessage(nullToEmpty(dto.getMessage()));
issueBuilder.addAllTags(dto.getTags());
@ -174,40 +170,29 @@ public class SearchResponseFormat {
issueBuilder.setDebt(effortValue);
issueBuilder.setEffort(effortValue);
}
Integer line = dto.getLine();
if (line != null) {
issueBuilder.setLine(line);
}
setNullable(dto.getLine(), issueBuilder::setLine);
completeIssueLocations(dto, issueBuilder);
issueBuilder.setAuthor(nullToEmpty(dto.getAuthorLogin()));
Date date = dto.getIssueCreationDate();
if (date != null) {
issueBuilder.setCreationDate(DateUtils.formatDateTime(date));
}
date = dto.getIssueUpdateDate();
if (date != null) {
issueBuilder.setUpdateDate(DateUtils.formatDateTime(date));
}
date = dto.getIssueCloseDate();
if (date != null) {
issueBuilder.setCloseDate(DateUtils.formatDateTime(date));
}
setNullable(dto.getIssueCreationDate(), issueBuilder::setCreationDate, DateUtils::formatDateTime);
setNullable(dto.getIssueUpdateDate(), issueBuilder::setUpdateDate, DateUtils::formatDateTime);
setNullable(dto.getIssueCloseDate(), issueBuilder::setCloseDate, DateUtils::formatDateTime);
}
private void completeIssueLocations(IssueDto dto, Issues.Issue.Builder issueBuilder) {
DbIssues.Locations locations = dto.parseLocations();
if (locations != null) {
if (locations.hasTextRange()) {
DbCommons.TextRange textRange = locations.getTextRange();
issueBuilder.setTextRange(convertTextRange(textRange));
}
for (DbIssues.Flow flow : locations.getFlowList()) {
Issues.Flow.Builder targetFlow = Issues.Flow.newBuilder();
for (DbIssues.Location flowLocation : flow.getLocationList()) {
targetFlow.addLocations(convertLocation(flowLocation));
}
issueBuilder.addFlows(targetFlow);
if (locations == null) {
return;
}
if (locations.hasTextRange()) {
DbCommons.TextRange textRange = locations.getTextRange();
issueBuilder.setTextRange(convertTextRange(textRange));
}
for (DbIssues.Flow flow : locations.getFlowList()) {
Issues.Flow.Builder targetFlow = Issues.Flow.newBuilder();
for (DbIssues.Location flowLocation : flow.getLocationList()) {
targetFlow.addLocations(convertLocation(flowLocation));
}
issueBuilder.addFlows(targetFlow);
}
}
@ -323,13 +308,10 @@ public class SearchResponseFormat {
// On a root project, parentProjectId is null but projectId is equal to itself, which make no sense.
if (!uuid.equals(dto.getRootUuid())) {
ComponentDto project = data.getComponentByUuid(dto.projectUuid());
if (project != null) {
builder.setProjectId(project.getId());
}
setNullable(project, builder::setProjectId, ComponentDto::getId);
ComponentDto subProject = data.getComponentByUuid(dto.getRootUuid());
if (subProject != null) {
builder.setSubProjectId(subProject.getId());
}
setNullable(subProject, builder::setSubProjectId, ComponentDto::getId);
}
result.add(builder.build());
}
@ -376,7 +358,7 @@ public class SearchResponseFormat {
valueBuilder.build();
}
} else {
wsFacet.addAllValues(Collections.<Common.FacetValue>emptyList());
wsFacet.addAllValues(Collections.emptyList());
}
wsFacets.addFacets(wsFacet);
}

View File

@ -26,6 +26,7 @@ import org.sonar.db.organization.OrganizationDto;
import org.sonarqube.ws.Organizations;
import static com.google.common.base.Preconditions.checkArgument;
import static org.sonar.core.util.Protobuf.setNullable;
/**
* Factorizes code and constants between Organization WS's actions.
@ -119,15 +120,9 @@ public class OrganizationsWsSupport {
.clear()
.setName(dto.getName())
.setKey(dto.getKey());
if (dto.getDescription() != null) {
builder.setDescription(dto.getDescription());
}
if (dto.getUrl() != null) {
builder.setUrl(dto.getUrl());
}
if (dto.getAvatarUrl() != null) {
builder.setAvatar(dto.getAvatarUrl());
}
setNullable(dto.getDescription(), builder::setDescription);
setNullable(dto.getUrl(), builder::setUrl);
setNullable(dto.getAvatarUrl(), builder::setAvatar);
return builder.build();
}
}

View File

@ -44,6 +44,7 @@ import org.sonarqube.ws.WsPermissions.Group;
import org.sonarqube.ws.WsPermissions.WsGroupsResponse;
import static java.util.Collections.emptyList;
import static org.sonar.core.util.Protobuf.setNullable;
import static org.sonar.db.permission.PermissionQuery.DEFAULT_PAGE_SIZE;
import static org.sonar.db.permission.PermissionQuery.RESULTS_MAX_SIZE;
import static org.sonar.db.permission.PermissionQuery.SEARCH_QUERY_MIN_LENGTH;
@ -131,9 +132,7 @@ public class GroupsAction implements PermissionsWsAction {
if (group.getId() != 0L) {
wsGroup.setId(String.valueOf(group.getId()));
}
if (group.getDescription() != null) {
wsGroup.setDescription(group.getDescription());
}
setNullable(group.getDescription(), wsGroup::setDescription);
wsGroup.addAllPermissions(permissionsByGroupId.get(group.getId()));
});

View File

@ -42,6 +42,7 @@ import org.sonarqube.ws.WsPermissions;
import org.sonarqube.ws.WsPermissions.UsersWsResponse;
import static java.util.Collections.emptyList;
import static org.sonar.core.util.Protobuf.setNullable;
import static org.sonar.db.permission.PermissionQuery.DEFAULT_PAGE_SIZE;
import static org.sonar.db.permission.PermissionQuery.RESULTS_MAX_SIZE;
import static org.sonar.db.permission.PermissionQuery.SEARCH_QUERY_MIN_LENGTH;
@ -144,13 +145,8 @@ public class UsersAction implements PermissionsWsAction {
WsPermissions.User.Builder userResponse = response.addUsersBuilder()
.setLogin(user.getLogin())
.addAllPermissions(permissionsByUserId.get(user.getId()));
if (user.getEmail() != null) {
userResponse.setEmail(user.getEmail());
}
if (user.getName() != null) {
userResponse.setName(user.getName());
}
setNullable(user.getEmail(), userResponse::setEmail);
setNullable(user.getName(), userResponse::setName);
});
response.getPagingBuilder()

View File

@ -25,6 +25,8 @@ import org.sonar.api.utils.DateUtils;
import org.sonar.db.permission.template.PermissionTemplateDto;
import org.sonarqube.ws.WsPermissions.PermissionTemplate;
import static org.sonar.core.util.Protobuf.setNullable;
public class PermissionTemplateDtoToPermissionTemplateResponse {
private PermissionTemplateDtoToPermissionTemplateResponse() {
@ -44,12 +46,8 @@ public class PermissionTemplateDtoToPermissionTemplateResponse {
.setName(permissionTemplate.getName())
.setCreatedAt(DateUtils.formatDateTime(permissionTemplate.getCreatedAt()))
.setUpdatedAt(DateUtils.formatDateTime(permissionTemplate.getUpdatedAt()));
if (permissionTemplate.getDescription() != null) {
permissionTemplateBuilder.setDescription(permissionTemplate.getDescription());
}
if (permissionTemplate.getKeyPattern() != null) {
permissionTemplateBuilder.setProjectKeyPattern(permissionTemplate.getKeyPattern());
}
setNullable(permissionTemplate.getDescription(), permissionTemplateBuilder::setDescription);
setNullable(permissionTemplate.getKeyPattern(), permissionTemplateBuilder::setProjectKeyPattern);
return permissionTemplateBuilder.build();
}
}

View File

@ -41,6 +41,7 @@ import org.sonarqube.ws.WsPermissions.SearchTemplatesWsResponse.TemplateIdQualif
import org.sonarqube.ws.client.permission.SearchTemplatesWsRequest;
import static org.sonar.api.utils.DateUtils.formatDateTime;
import static org.sonar.core.util.Protobuf.setNullable;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createOrganizationParameter;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_ORGANIZATION_KEY;
@ -122,12 +123,8 @@ public class SearchTemplatesAction implements PermissionsWsAction {
.setName(templateDto.getName())
.setCreatedAt(formatDateTime(templateDto.getCreatedAt()))
.setUpdatedAt(formatDateTime(templateDto.getUpdatedAt()));
if (templateDto.getKeyPattern() != null) {
templateBuilder.setProjectKeyPattern(templateDto.getKeyPattern());
}
if (templateDto.getDescription() != null) {
templateBuilder.setDescription(templateDto.getDescription());
}
setNullable(templateDto.getKeyPattern(), templateBuilder::setProjectKeyPattern);
setNullable(templateDto.getDescription(), templateBuilder::setDescription);
for (String permission : ProjectPermissions.ALL) {
templateBuilder.addPermissions(
permissionResponse

View File

@ -44,6 +44,7 @@ import org.sonarqube.ws.WsPermissions;
import static org.sonar.api.server.ws.WebService.Param.PAGE;
import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;
import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY;
import static org.sonar.core.util.Protobuf.setNullable;
import static org.sonar.db.permission.PermissionQuery.DEFAULT_PAGE_SIZE;
import static org.sonar.db.permission.PermissionQuery.RESULTS_MAX_SIZE;
import static org.sonar.db.permission.PermissionQuery.SEARCH_QUERY_MIN_LENGTH;
@ -128,9 +129,7 @@ public class TemplateGroupsAction implements PermissionsWsAction {
if (group.getId() != 0L) {
wsGroup.setId(String.valueOf(group.getId()));
}
if (group.getDescription() != null) {
wsGroup.setDescription(group.getDescription());
}
setNullable(group.getDescription(), wsGroup::setDescription);
wsGroup.addAllPermissions(permissionsByGroupId.get(group.getId()));
});

View File

@ -45,6 +45,7 @@ import org.sonarqube.ws.WsPermissions.UsersWsResponse;
import static org.sonar.api.server.ws.WebService.Param.PAGE;
import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;
import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY;
import static org.sonar.core.util.Protobuf.setNullable;
import static org.sonar.db.permission.PermissionQuery.DEFAULT_PAGE_SIZE;
import static org.sonar.db.permission.PermissionQuery.RESULTS_MAX_SIZE;
import static org.sonar.db.permission.PermissionQuery.SEARCH_QUERY_MIN_LENGTH;
@ -130,12 +131,8 @@ public class TemplateUsersAction implements PermissionsWsAction {
WsPermissions.User.Builder userResponse = responseBuilder.addUsersBuilder()
.setLogin(user.getLogin())
.addAllPermissions(permissionsByUserId.get(user.getId()));
if (user.getEmail() != null) {
userResponse.setEmail(user.getEmail());
}
if (user.getName() != null) {
userResponse.setName(user.getName());
}
setNullable(user.getEmail(), userResponse::setEmail);
setNullable(user.getName(), userResponse::setName);
});
responseBuilder.getPagingBuilder()
.setPageIndex(paging.pageIndex())

View File

@ -35,8 +35,10 @@ import org.sonarqube.ws.WsProjects.SearchMyProjectsWsResponse.Link;
import org.sonarqube.ws.WsProjects.SearchMyProjectsWsResponse.Project;
import org.sonarqube.ws.client.project.SearchMyProjectsRequest;
import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.base.Strings.isNullOrEmpty;
import static java.lang.String.format;
import static org.sonar.core.util.Protobuf.setNullable;
import static org.sonar.server.ws.WsUtils.checkRequest;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
@ -146,9 +148,7 @@ public class SearchMyProjectsAction implements ProjectsWsAction {
if (qualityGate.isPresent()) {
project.setQualityGate(qualityGate.get());
}
if (!isNullOrEmpty(dto.description())) {
project.setDescription(dto.description());
}
setNullable(emptyToNull(dto.description()), project::setDescription);
data.projectLinksFor(dto.uuid()).stream()
.map(ProjectLinkDtoToWs.INSTANCE)

View File

@ -29,6 +29,8 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.function.Function;
import javax.annotation.Nullable;
import org.apache.commons.io.IOUtils;
/**
@ -169,4 +171,41 @@ public class Protobuf {
IOUtils.closeQuietly(input);
}
}
/**
* Call a setter method of {@link com.google.protobuf.GeneratedMessage.Builder} if the parameter
* is not null. Do nothing if parameter is null.
* <br/>
* This utility method is convenient as the setter methods of Protobuf 2 do not accept
* {@code null} parameters. It avoid increasing complexity with "if not null" conditions.
* <br/>
* Example:
* <pre>
* setNullable(dto.getLine(), issueBuilder::setLine);
* </pre>
*/
public static <PARAM> void setNullable(@Nullable PARAM parameter, Function<PARAM, ?> setter) {
if (parameter != null) {
setter.apply(parameter);
}
}
/**
* Same as {@link #setNullable(Object, Function)} but the parameter is converted by the function "{@code paramConverter}"
* before being applied to setter. If the converter returns {@code null}, then setter method
* is not called.
* <br/>
* Example:
* <pre>
* setNullable(dto.getIssueCreationDate(), issueBuilder::setCreationDate, DateUtils::formatDateTime);
* </pre>
* @see #setNullable(Object, Function)
*/
public static <PARAM, PARAM2> void setNullable(@Nullable PARAM param, Function<PARAM2, ?> setter,
Function<PARAM, PARAM2> paramConverter) {
if (param != null) {
PARAM2 output = paramConverter.apply(param);
setNullable(output, setter);
}
}
}