diff --git a/src/main/java/ubc/pavlab/rdp/controllers/AbstractSearchController.java b/src/main/java/ubc/pavlab/rdp/controllers/AbstractSearchController.java index 2b979666..440300e1 100644 --- a/src/main/java/ubc/pavlab/rdp/controllers/AbstractSearchController.java +++ b/src/main/java/ubc/pavlab/rdp/controllers/AbstractSearchController.java @@ -6,6 +6,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; +import org.springframework.lang.Nullable; import org.springframework.validation.Errors; import org.springframework.validation.Validator; import org.springframework.web.bind.WebDataBinder; @@ -60,14 +61,18 @@ public abstract class AbstractSearchController { @Data @NoArgsConstructor @AllArgsConstructor(access = AccessLevel.PROTECTED) - protected static class SearchParams { + public static class SearchParams { private boolean iSearch; + @Nullable private Set researcherPositions; + @Nullable private Set researcherCategories; + @Nullable private Set organUberonIds; /** * Order matters here because we want to preserve the UI rendering. */ + @Nullable private List ontologyTermIds; /** @@ -81,14 +86,14 @@ public boolean isEmpty() { @Data @EqualsAndHashCode(callSuper = true) @NoArgsConstructor - protected static class UserSearchParams extends SearchParams { + public static class UserSearchParams extends SearchParams { @NotNull private String nameLike; private boolean prefix; @NotNull private String descriptionLike; - public UserSearchParams( String nameLike, boolean prefix, String descriptionLike, boolean iSearch, Set researcherPositions, Set researcherCategories, Set organUberonIds, List ontologyTermIds ) { + public UserSearchParams( String nameLike, boolean prefix, String descriptionLike, boolean iSearch, @Nullable Set researcherPositions, @Nullable Set researcherCategories, @Nullable Set organUberonIds, @Nullable List ontologyTermIds ) { super( iSearch, researcherPositions, researcherCategories, organUberonIds, ontologyTermIds ); this.nameLike = nameLike; this.prefix = prefix; @@ -101,7 +106,7 @@ public boolean isEmpty() { } } - protected static class UserSearchParamsValidator implements Validator { + public static class UserSearchParamsValidator implements Validator { @Override public boolean supports( Class clazz ) { @@ -129,9 +134,10 @@ protected static class GeneSearchParams extends SearchParams { @NotNull private GeneInfo gene; private Set tiers; + @Nullable private Taxon orthologTaxon; - public GeneSearchParams( GeneInfo gene, Set tiers, Taxon orthologTaxon, boolean iSearch, Set researcherPositions, Set researcherCategories, Set organUberonIds, List ontologyTermIds ) { + public GeneSearchParams( GeneInfo gene, Set tiers, @Nullable Taxon orthologTaxon, boolean iSearch, @Nullable Set researcherPositions, @Nullable Set researcherCategories, @Nullable Set organUberonIds, @Nullable List ontologyTermIds ) { super( iSearch, researcherPositions, researcherCategories, organUberonIds, ontologyTermIds ); this.gene = gene; this.tiers = tiers; @@ -371,17 +377,13 @@ private static Map collectAsManyFuturesAsPossible( Map organsFromUberonIds( Set organUberonIds ) { + @Nullable + protected Collection organsFromUberonIds( @Nullable Set organUberonIds ) { return organUberonIds == null ? null : organInfoService.findByUberonIdIn( organUberonIds ); } - /** - * No need to perform the same - * - * @param ontologyTermIds - * @return - */ - protected Map> ontologyTermsFromIds( List ontologyTermIds ) { + @Nullable + protected Map> ontologyTermsFromIds( @Nullable List ontologyTermIds ) { return ontologyTermIds == null ? null : ontologyService.findAllTermsByIdIn( ontologyTermIds ).stream() .collect( Collectors.groupingBy( OntologyTermInfo::getOntology, Collectors.toSet() ) ); } diff --git a/src/main/java/ubc/pavlab/rdp/controllers/AdminController.java b/src/main/java/ubc/pavlab/rdp/controllers/AdminController.java index 71e96a46..377d95d2 100644 --- a/src/main/java/ubc/pavlab/rdp/controllers/AdminController.java +++ b/src/main/java/ubc/pavlab/rdp/controllers/AdminController.java @@ -19,6 +19,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.lang.Nullable; import org.springframework.security.access.annotation.Secured; import org.springframework.security.concurrent.DelegatingSecurityContextRunnable; import org.springframework.stereotype.Controller; @@ -713,7 +714,7 @@ public Object importReactomePathways( RedirectAttributes redirectAttributes ) { } @PostMapping("/admin/ontologies/{ontology}/update-reactome-pathways") - public Object updateReactomePathways( @PathVariable(required = false) Ontology ontology, RedirectAttributes redirectAttributes, Locale locale ) { + public Object updateReactomePathways( @PathVariable(required = false) @Nullable Ontology ontology, RedirectAttributes redirectAttributes, Locale locale ) { // null-check is not necessary, but can save a database call if ( ontology == null || !ontology.equals( reactomeService.findPathwaysOntology() ) ) { return new ModelAndView( "error/404", HttpStatus.NOT_FOUND ) @@ -721,8 +722,16 @@ public Object updateReactomePathways( @PathVariable(required = false) Ontology o } try { Ontology reactomeOntology = reactomeService.updatePathwaysOntology(); - redirectAttributes.addFlashAttribute( "message", "Successfully updated Reactome pathways ontology." ); - return "redirect:/admin/ontologies/" + reactomeOntology.getId(); + if ( reactomeOntology != null ) { + redirectAttributes.addFlashAttribute( "message", "Successfully updated Reactome pathways ontology." ); + return "redirect:/admin/ontologies/" + reactomeOntology.getId(); + } else { + String message = "It seems that Reactome ontology does not setup."; + log.error( message ); + redirectAttributes.addFlashAttribute( "message", message ); + redirectAttributes.addFlashAttribute( "error", Boolean.TRUE ); + return "redirect:/admin/ontologies"; + } } catch ( ReactomeException e ) { log.error( "Failed to update Reactome pathways. Could this be an issue with the ontology configuration?", e ); redirectAttributes.addFlashAttribute( "message", "Failed to update Reactome pathways: " + e.getMessage() + "." ); @@ -735,9 +744,9 @@ public Object updateReactomePathways( @PathVariable(required = false) Ontology o * Update Reactome Pathways summations. */ @PostMapping(value = "/admin/ontologies/{ontology}/update-reactome-pathway-summations") - public Object updateReactomePathwaySummations( @PathVariable(required = false) Ontology ontology, Locale locale ) { + public Object updateReactomePathwaySummations( @PathVariable(required = false) @Nullable Ontology ontology, Locale locale ) { // null-check is not necessary, but can save a database call - if ( ontology == null || !reactomeService.findPathwaysOntology().equals( ontology ) ) { + if ( ontology == null || !Objects.equals( reactomeService.findPathwaysOntology(), ontology ) ) { return new ModelAndView( "error/404", HttpStatus.NOT_FOUND ) .addObject( "message", messageSource.getMessage( "AdminController.ontologyNotFoundById", null, locale ) ); } @@ -756,9 +765,9 @@ public Object updateReactomePathwaySummations( @PathVariable(required = false) O * @see #updateReactomePathwaySummations(Ontology, Locale) */ @GetMapping(value = "/admin/ontologies/{ontology}/update-reactome-pathway-summations", produces = MediaType.TEXT_EVENT_STREAM_VALUE) - public Object updateReactomePathwaySummationsSse( @PathVariable(required = false) Ontology ontology, Locale locale ) { + public Object updateReactomePathwaySummationsSse( @PathVariable(required = false) @Nullable Ontology ontology, Locale locale ) { // null-check is not necessary, but can save a database call - if ( ontology == null || !reactomeService.findPathwaysOntology().equals( ontology ) ) { + if ( ontology == null || !Objects.equals( reactomeService.findPathwaysOntology(), ontology ) ) { return ResponseEntity.status( HttpStatus.NOT_FOUND ) .body( messageSource.getMessage( "AdminController.ontologyNotFoundById", null, locale ) ); } @@ -1011,6 +1020,7 @@ public static class ImportOntologyForm { private URL ontologyUrl; private MultipartFile ontologyFile; + @Nullable public String getFilename() { if ( ontologyUrl != null ) { // path cannot be null, but it can be empty if missing (i.e. http://github.com) @@ -1034,13 +1044,13 @@ private Reader getReaderForImportOntologyForm( ImportOntologyForm importOntology } else if ( !isMultipartFileEmpty( importOntologyForm.ontologyFile ) ) { is = importOntologyForm.ontologyFile.getInputStream(); } else { - return null; + throw new RuntimeException( "No reader can be created from the import ontology form." ); } boolean hasGzipExtension = FilenameUtils.isExtension( importOntologyForm.getFilename(), "gz" ); return new InputStreamReader( hasGzipExtension ? new GZIPInputStream( is ) : is ); } - private static boolean isMultipartFileEmpty( MultipartFile mp ) { + private static boolean isMultipartFileEmpty( @Nullable MultipartFile mp ) { return mp == null || mp.isEmpty(); } diff --git a/src/main/java/ubc/pavlab/rdp/controllers/ApiController.java b/src/main/java/ubc/pavlab/rdp/controllers/ApiController.java index 45bc361c..6a0b857c 100644 --- a/src/main/java/ubc/pavlab/rdp/controllers/ApiController.java +++ b/src/main/java/ubc/pavlab/rdp/controllers/ApiController.java @@ -12,6 +12,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.lang.Nullable; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.core.Authentication; @@ -179,7 +180,7 @@ public Page getOntologyTerms( @PathVariable String ontol } @GetMapping(value = "/api/ontologies/{ontologyName}/terms", params = { "ontologyTermIds" }, produces = MediaType.APPLICATION_JSON_VALUE) - public List getOntologyTermsByOntologyNameAndTermIds( @PathVariable String ontologyName, @RequestParam List ontologyTermIds, Locale locale ) { + public List getOntologyTermsByOntologyNameAndTermIds( @PathVariable String ontologyName, @Nullable @RequestParam List ontologyTermIds, Locale locale ) { Ontology ontology = ontologyService.findByName( ontologyName ); if ( ontology == null || !ontology.isActive() ) { throw new ApiException( HttpStatus.NOT_FOUND, String.format( locale, "No ontology %s.", ontologyName ) ); @@ -247,13 +248,13 @@ public List searchUsersByNameAndDescription( @RequestParam String nameLike @GetMapping(value = "/api/genes/search", params = { "symbol", "taxonId" }, produces = MediaType.APPLICATION_JSON_VALUE) public List searchUsersByGeneSymbol( @RequestParam String symbol, @RequestParam Integer taxonId, - @RequestParam(required = false) Set tiers, - @RequestParam(required = false) Integer orthologTaxonId, - @RequestParam(required = false) Set researcherPositions, - @RequestParam(required = false) Set researcherCategories, - @RequestParam(required = false) Set organUberonIds, - @RequestParam(required = false) List ontologyNames, - @RequestParam(required = false) List ontologyTermIds, + @Nullable @RequestParam(required = false) Set tiers, + @Nullable @RequestParam(required = false) Integer orthologTaxonId, + @Nullable @RequestParam(required = false) Set researcherPositions, + @Nullable @RequestParam(required = false) Set researcherCategories, + @Nullable @RequestParam(required = false) Set organUberonIds, + @Nullable @RequestParam(required = false) List ontologyNames, + @Nullable @RequestParam(required = false) List ontologyTermIds, Locale locale ) { Taxon taxon = taxonService.findById( taxonId ); @@ -448,11 +449,13 @@ private Set restrictTiers( Set tiers ) { .collect( Collectors.toSet() ); } - private Collection organsFromUberonIds( Set organUberonIds ) { + @Nullable + private Collection organsFromUberonIds( @Nullable Set organUberonIds ) { return organUberonIds == null ? null : organInfoService.findByUberonIdIn( organUberonIds ); } - private Map> ontologyTermsFromOntologyWithTermIds( List ontologyNames, List termIds ) { + @Nullable + private Map> ontologyTermsFromOntologyWithTermIds( @Nullable List ontologyNames, @Nullable List termIds ) { if ( ontologyNames == null || termIds == null ) { return null; } diff --git a/src/main/java/ubc/pavlab/rdp/controllers/GeneController.java b/src/main/java/ubc/pavlab/rdp/controllers/GeneController.java index 1a4f1ee3..ec8c435e 100644 --- a/src/main/java/ubc/pavlab/rdp/controllers/GeneController.java +++ b/src/main/java/ubc/pavlab/rdp/controllers/GeneController.java @@ -4,7 +4,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; import ubc.pavlab.rdp.model.GeneInfo; import ubc.pavlab.rdp.model.Taxon; import ubc.pavlab.rdp.services.GOService; @@ -82,6 +85,10 @@ public Object getGeneByTaxonAndSymbol( @PathVariable Integer taxonId, @PathVaria if ( taxon == null ) { return ResponseEntity.notFound().build(); } - return geneService.findBySymbolAndTaxon( symbol, taxon ); + GeneInfo gene = geneService.findBySymbolAndTaxon( symbol, taxon ); + if ( gene == null ) { + return ResponseEntity.notFound().build(); + } + return gene; } } diff --git a/src/main/java/ubc/pavlab/rdp/controllers/SearchController.java b/src/main/java/ubc/pavlab/rdp/controllers/SearchController.java index 7046518c..17db8b26 100644 --- a/src/main/java/ubc/pavlab/rdp/controllers/SearchController.java +++ b/src/main/java/ubc/pavlab/rdp/controllers/SearchController.java @@ -8,6 +8,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.lang.Nullable; import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; @@ -30,7 +31,6 @@ import ubc.pavlab.rdp.model.ontology.OntologyTermInfo; import ubc.pavlab.rdp.security.Permissions; import ubc.pavlab.rdp.services.*; -import ubc.pavlab.rdp.services.RemoteResourceService; import ubc.pavlab.rdp.settings.ApplicationSettings; import ubc.pavlab.rdp.util.SearchResult; @@ -41,6 +41,8 @@ import java.util.*; import java.util.stream.Collectors; +import static java.util.Objects.requireNonNull; + /** * Created by mjacobson on 05/02/18. */ @@ -136,10 +138,10 @@ public Object searchUsers( @Valid UserSearchParams userSearchParams, BindingResu public ModelAndView searchUsersByName( @RequestParam String nameLike, @RequestParam(required = false) boolean prefix, @RequestParam boolean iSearch, - @RequestParam(required = false) Set researcherPositions, - @RequestParam(required = false) Set researcherCategories, - @RequestParam(required = false) Set organUberonIds, - @RequestParam(required = false) List ontologyTermIds, + @RequestParam(required = false) @Nullable Set researcherPositions, + @RequestParam(required = false) @Nullable Set researcherCategories, + @RequestParam(required = false) @Nullable Set organUberonIds, + @RequestParam(required = false) @Nullable List ontologyTermIds, Locale locale ) { Collection users; if ( prefix ) { @@ -185,10 +187,10 @@ public ModelAndView searchUsersByName( @RequestParam String nameLike, @GetMapping(value = "/search", params = { "descriptionLike" }) public ModelAndView searchUsersByDescription( @RequestParam String descriptionLike, @RequestParam boolean iSearch, - @RequestParam(required = false) Set researcherPositions, - @RequestParam(required = false) Set researcherCategories, - @RequestParam(required = false) Set organUberonIds, - @RequestParam(required = false) List ontologyTermIds, + @RequestParam(required = false) @Nullable Set researcherPositions, + @RequestParam(required = false) @Nullable Set researcherCategories, + @RequestParam(required = false) @Nullable Set organUberonIds, + @RequestParam(required = false) @Nullable List ontologyTermIds, Locale locale ) { ModelAndView modelAndView = new ModelAndView( "search" ) .addObject( "activeSearchMode", ApplicationSettings.SearchSettings.SearchMode.BY_RESEARCHER ) @@ -229,12 +231,12 @@ public ModelAndView searchUsersByDescription( @RequestParam String descriptionLi public ModelAndView searchUsersByGene( @RequestParam String symbol, @RequestParam Integer taxonId, @RequestParam boolean iSearch, - @RequestParam(required = false) Set tiers, - @RequestParam(required = false) Integer orthologTaxonId, - @RequestParam(required = false) Set researcherPositions, - @RequestParam(required = false) Set researcherCategories, - @RequestParam(required = false) Set organUberonIds, - @RequestParam(required = false) List ontologyTermIds, + @RequestParam(required = false) @Nullable Set tiers, + @RequestParam(required = false) @Nullable Integer orthologTaxonId, + @RequestParam(required = false) @Nullable Set researcherPositions, + @RequestParam(required = false) @Nullable Set researcherCategories, + @RequestParam(required = false) @Nullable Set organUberonIds, + @RequestParam(required = false) @Nullable List ontologyTermIds, Locale locale ) { // Only look for orthologs when taxon is human if ( taxonId != 9606 ) { @@ -324,7 +326,7 @@ public ModelAndView searchUsersByGene( @RequestParam String symbol, @PreAuthorize("hasPermission(null, #remoteHost == null ? 'search' : 'international-search')") @GetMapping(value = "/search/user/{userId}") public ModelAndView getUser( @PathVariable Integer userId, - @RequestParam(required = false) String remoteHost ) { + @RequestParam(required = false) @Nullable String remoteHost ) { User user = userService.findCurrentUser(); User viewUser; if ( remoteHost != null && !remoteHost.isEmpty() ) { @@ -372,7 +374,7 @@ public static class RequestAccessForm { @PreAuthorize("hasPermission(null, 'search') and hasAnyRole('USER', 'ADMIN')") @GetMapping("/search/gene/by-anonymous-id/{anonymousId}/request-access") public Object requestGeneAccessView( @PathVariable UUID anonymousId, - @RequestParam(required = false) URI remoteHost, + @RequestParam(required = false) @Nullable URI remoteHost, RedirectAttributes redirectAttributes ) { if ( remoteHost != null ) { try { @@ -402,16 +404,16 @@ public ModelAndView requestGeneAccess( @PathVariable UUID anonymousId, @Valid RequestAccessForm requestAccessForm, BindingResult bindingResult, RedirectAttributes redirectAttributes ) { - UserGene userGene = userService.findUserGeneByAnonymousIdNoAuth( anonymousId ); - if ( userGene == null ) { + User user = requireNonNull( userService.findCurrentUser() ); + UserGene requestedUserGene = userService.findUserGeneByAnonymousIdNoAuth( anonymousId ); + if ( requestedUserGene == null ) { return new ModelAndView( "error/404", HttpStatus.NOT_FOUND ); } - if ( bindingResult.hasErrors() ) { return new ModelAndView( "search/request-access", HttpStatus.BAD_REQUEST ) - .addObject( "userGene", userService.anonymizeUserGene( userGene ) ); + .addObject( "userGene", userService.anonymizeUserGene( requestedUserGene ) ); } else { - userService.sendGeneAccessRequest( userService.findCurrentUser(), userGene, requestAccessForm.getReason() ); + userService.sendGeneAccessRequest( user, requestedUserGene, requestAccessForm.getReason() ); redirectAttributes.addFlashAttribute( "message", "An access request has been sent and will be reviewed." ); return new ModelAndView( "redirect:/search" ); } @@ -425,7 +427,7 @@ public ModelAndView requestGeneAccess( @PathVariable UUID anonymousId, */ @ResponseBody @GetMapping("/search/ontology-terms/autocomplete") - public Object autocompleteTerms( @RequestParam String query, @RequestParam(required = false) Integer ontologyId, Locale locale ) { + public Object autocompleteTerms( @RequestParam String query, @RequestParam(required = false) @Nullable Integer ontologyId, Locale locale ) { if ( ontologyId != null ) { Ontology ontology = ontologyService.findById( ontologyId ); if ( ontology == null || !ontology.isActive() ) { diff --git a/src/main/java/ubc/pavlab/rdp/controllers/SearchViewController.java b/src/main/java/ubc/pavlab/rdp/controllers/SearchViewController.java index 15e0fa3c..33dd4885 100644 --- a/src/main/java/ubc/pavlab/rdp/controllers/SearchViewController.java +++ b/src/main/java/ubc/pavlab/rdp/controllers/SearchViewController.java @@ -5,6 +5,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.http.HttpStatus; +import org.springframework.lang.Nullable; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; @@ -32,6 +33,8 @@ import java.util.*; import java.util.stream.Collectors; +import static java.util.Objects.requireNonNull; + @Controller @CommonsLog public class SearchViewController extends AbstractSearchController { @@ -91,10 +94,10 @@ public Object searchItlUsers( @Valid UserSearchParams userSearchParams, BindingR @GetMapping(value = "/search/view/international", params = { "nameLike" }) public ModelAndView searchItlUsersByNameView( @RequestParam String nameLike, @RequestParam(required = false) boolean prefix, - @RequestParam(required = false) Set researcherPositions, - @RequestParam(required = false) Set researcherCategories, - @RequestParam(required = false) Set organUberonIds, - @RequestParam(required = false) List ontologyTermIds ) { + @RequestParam(required = false) @Nullable Set researcherPositions, + @RequestParam(required = false) @Nullable Set researcherCategories, + @RequestParam(required = false) @Nullable Set organUberonIds, + @RequestParam(required = false) @Nullable List ontologyTermIds ) { if ( nameLike.isEmpty() ) { return new ModelAndView( "fragments/error::message", HttpStatus.BAD_REQUEST ) .addObject( "errorMessage", "Researcher name cannot be empty." ); @@ -108,10 +111,10 @@ public ModelAndView searchItlUsersByNameView( @RequestParam String nameLike, @PreAuthorize("hasPermission(null, 'international-search')") @GetMapping(value = "/search/view/international", params = { "descriptionLike" }) public ModelAndView searchItlUsersByDescriptionView( @RequestParam String descriptionLike, - @RequestParam(required = false) Set researcherPositions, - @RequestParam(required = false) Set researcherCategories, - @RequestParam(required = false) Set organUberonIds, - @RequestParam(required = false) List ontologyTermIds ) { + @RequestParam(required = false) @Nullable Set researcherPositions, + @RequestParam(required = false) @Nullable Set researcherCategories, + @RequestParam(required = false) @Nullable Set organUberonIds, + @RequestParam(required = false) @Nullable List ontologyTermIds ) { if ( descriptionLike.isEmpty() ) { return new ModelAndView( "fragments/error::message", HttpStatus.BAD_REQUEST ) .addObject( "errorMessage", "Research interests cannot be empty." ); @@ -146,10 +149,10 @@ public Object searchUsersView( @Valid UserSearchParams userSearchParams, Binding @GetMapping(value = "/search/view", params = { "nameLike" }) public Object searchUsersByNameView( @RequestParam String nameLike, @RequestParam(required = false) boolean prefix, - @RequestParam(required = false) Set researcherPositions, - @RequestParam(required = false) Set researcherCategories, - @RequestParam(required = false) Set organUberonIds, - @RequestParam(required = false) List ontologyTermIds, + @RequestParam(required = false) @Nullable Set researcherPositions, + @RequestParam(required = false) @Nullable Set researcherCategories, + @RequestParam(required = false) @Nullable Set organUberonIds, + @RequestParam(required = false) @Nullable List ontologyTermIds, @RequestParam(required = false) boolean summarize, Locale locale ) { if ( nameLike.isEmpty() ) { @@ -172,10 +175,10 @@ public Object searchUsersByNameView( @RequestParam String nameLike, @PreAuthorize("hasPermission(null, 'search')") @GetMapping(value = "/search/view", params = { "descriptionLike" }) public Object searchUsersByDescriptionView( @RequestParam String descriptionLike, - @RequestParam(required = false) Set researcherPositions, - @RequestParam(required = false) Set researcherCategories, - @RequestParam(required = false) Set organUberonIds, - @RequestParam(required = false) List ontologyTermIds, + @RequestParam(required = false) @Nullable Set researcherPositions, + @RequestParam(required = false) @Nullable Set researcherCategories, + @RequestParam(required = false) @Nullable Set organUberonIds, + @RequestParam(required = false) @Nullable List ontologyTermIds, @RequestParam(required = false) boolean summarize, Locale locale ) { if ( descriptionLike.isEmpty() ) { @@ -195,12 +198,12 @@ public Object searchUsersByDescriptionView( @RequestParam String descriptionLike @GetMapping(value = "/search/view") public ModelAndView searchUsersByGeneView( @RequestParam String symbol, @RequestParam Integer taxonId, - @RequestParam(required = false) Set tiers, - @RequestParam(required = false) Integer orthologTaxonId, - @RequestParam(required = false) Set researcherPositions, - @RequestParam(required = false) Set researcherCategories, - @RequestParam(required = false) Set organUberonIds, - @RequestParam(required = false) List ontologyTermIds, + @RequestParam(required = false) @Nullable Set tiers, + @RequestParam(required = false) @Nullable Integer orthologTaxonId, + @RequestParam(required = false) @Nullable Set researcherPositions, + @RequestParam(required = false) @Nullable Set researcherCategories, + @RequestParam(required = false) @Nullable Set organUberonIds, + @RequestParam(required = false) @Nullable List ontologyTermIds, @RequestParam(required = false) boolean summarize, Locale locale ) { if ( tiers == null ) { @@ -334,12 +337,12 @@ public ModelAndView getAvailableTermsByPartner( @RequestParam(required = false) @GetMapping(value = "/search/view/international", params = { "symbol", "taxonId" }) public ModelAndView searchItlUsersByGeneView( @RequestParam String symbol, @RequestParam Integer taxonId, - @RequestParam(required = false) Set tiers, - @RequestParam(required = false) Integer orthologTaxonId, - @RequestParam(required = false) Set researcherPositions, - @RequestParam(required = false) Set researcherCategories, - @RequestParam(required = false) Set organUberonIds, - @RequestParam(required = false) List ontologyTermIds ) { + @RequestParam(required = false) @Nullable Set tiers, + @RequestParam(required = false) @Nullable Integer orthologTaxonId, + @RequestParam(required = false) @Nullable Set researcherPositions, + @RequestParam(required = false) @Nullable Set researcherCategories, + @RequestParam(required = false) @Nullable Set organUberonIds, + @RequestParam(required = false) @Nullable List ontologyTermIds ) { // Only look for orthologs when taxon is human if ( taxonId != 9606 ) { orthologTaxonId = null; @@ -354,7 +357,7 @@ public ModelAndView searchItlUsersByGeneView( @RequestParam String symbol, .addObject( "errorMessage", "Gene symbol cannot be empty." ); } - Taxon taxon = taxonService.findById( taxonId ); + Taxon taxon = requireNonNull( taxonService.findById( taxonId ) ); Collection userGenes = remoteResourceService.findGenesBySymbol( symbol, taxon, tiers, orthologTaxonId, researcherPositions, researcherCategories, organUberonIds, ontologyTermsFromIds( ontologyTermIds ) ); return new ModelAndView( "fragments/user-table::usergenes-table" ) @@ -365,7 +368,7 @@ public ModelAndView searchItlUsersByGeneView( @RequestParam String symbol, @PreAuthorize("hasPermission(null, #remoteHost == null ? 'search' : 'international-search')") @GetMapping(value = "/search/view/user-preview/{userId}") public ModelAndView previewUser( @PathVariable Integer userId, - @RequestParam(required = false) String remoteHost ) { + @RequestParam(required = false) @Nullable String remoteHost ) { User user; if ( remoteHost != null ) { URI remoteHostUri = URI.create( remoteHost ); @@ -388,7 +391,7 @@ public ModelAndView previewUser( @PathVariable Integer userId, @PreAuthorize("hasPermission(null, #remoteHost == null ? 'search' : 'international-search')") @GetMapping(value = "/search/view/user-preview/by-anonymous-id/{anonymousId}") public ModelAndView previewAnonymousUser( @PathVariable UUID anonymousId, - @RequestParam(required = false) String remoteHost ) { + @RequestParam(required = false) @Nullable String remoteHost ) { User user; if ( remoteHost != null ) { URI remoteHostUri = URI.create( remoteHost ); @@ -403,12 +406,15 @@ public ModelAndView previewAnonymousUser( @PathVariable UUID anonymousId, .addObject( "errorMessage", "Error querying remote anonymous user." ); } } else { - user = userService.anonymizeUser( userService.findUserByAnonymousIdNoAuth( anonymousId ) ); + user = userService.findUserByAnonymousIdNoAuth( anonymousId ); + if ( user != null ) { + user = userService.anonymizeUser( user ); + } } return previewUserModelAndView( user ); } - private static ModelAndView previewUserModelAndView( User user ) { + private static ModelAndView previewUserModelAndView( @Nullable User user ) { if ( user == null ) { return new ModelAndView( "fragments/error::message", HttpStatus.NOT_FOUND ) .addObject( "errorMessage", "Could not find user by given identifier." ); diff --git a/src/main/java/ubc/pavlab/rdp/controllers/UserController.java b/src/main/java/ubc/pavlab/rdp/controllers/UserController.java index 6eb60538..a92f278a 100644 --- a/src/main/java/ubc/pavlab/rdp/controllers/UserController.java +++ b/src/main/java/ubc/pavlab/rdp/controllers/UserController.java @@ -43,6 +43,7 @@ import java.util.*; import java.util.stream.Collectors; +import static java.util.Objects.requireNonNull; import static java.util.function.Function.identity; import static ubc.pavlab.rdp.util.CollectionUtils.toNullableMap; @@ -74,15 +75,14 @@ public class UserController { @GetMapping(value = { "/user/home" }) public ModelAndView userHome() { - ModelAndView modelAndView = new ModelAndView( "user/home" ); - modelAndView.addObject( "user", userService.findCurrentUser() ); - return modelAndView; + return new ModelAndView( "user/home" ) + .addObject( "user", requireNonNull( userService.findCurrentUser() ) ); } @GetMapping(value = { "/user/model/{taxonId}" }) public ModelAndView model( @PathVariable Integer taxonId ) { ModelAndView modelAndView = new ModelAndView( "user/model" ); - User user = userService.findCurrentUser(); + User user = requireNonNull( userService.findCurrentUser() ); Taxon taxon = taxonService.findById( taxonId ); if ( taxon == null ) { modelAndView.setViewName( "error/404" ); @@ -100,7 +100,7 @@ public ModelAndView model( @PathVariable Integer taxonId ) { @GetMapping(value = "/user/taxon/{taxonId}/term/{goId}/gene/view") public ModelAndView getTermsGenesForTaxon( @PathVariable Integer taxonId, @PathVariable String goId ) { ModelAndView modelAndView = new ModelAndView( "fragments/gene-table::gene-table" ); - User user = userService.findCurrentUser(); + User user = requireNonNull( userService.findCurrentUser() ); Taxon taxon = taxonService.findById( taxonId ); if ( taxon == null ) { @@ -156,12 +156,11 @@ public ModelAndView faq() { @GetMapping(value = { "/user/support" }) public ModelAndView support( SupportForm supportForm ) { - ModelAndView modelAndView = new ModelAndView( "user/support" ); - User user = userService.findCurrentUser(); + User user = requireNonNull( userService.findCurrentUser() ); supportForm.setName( user.getProfile().getFullName() ); - modelAndView.addObject( "user", user ); - modelAndView.addObject( "supportForm", supportForm ); - return modelAndView; + return new ModelAndView( "user/support" ) + .addObject( "user", user ) + .addObject( "supportForm", supportForm ); } @Data @@ -226,7 +225,7 @@ public void initBinder( WebDataBinder webDataBinder ) { @PostMapping(value = { "/user/support" }) public ModelAndView supportPost( @RequestHeader(value = "User-Agent", required = false) String userAgent, @Valid @ModelAttribute("supportForm") SupportForm supportForm, BindingResult bindingResult, Locale locale ) { ModelAndView modelAndView = new ModelAndView( "user/support" ); - User user = userService.findCurrentUser(); + User user = requireNonNull( userService.findCurrentUser() ); modelAndView.addObject( "user", user ); // ignore empty attachment @@ -309,7 +308,7 @@ public ModelAndView changePassword( @Valid PasswordChange passwordChange, Bindin @PostMapping("/user/resend-contact-email-verification") public Object resendContactEmailVerification( RedirectAttributes redirectAttributes, Locale locale ) { - User user = userService.findCurrentUser(); + User user = requireNonNull( userService.findCurrentUser() ); if ( user.getProfile().isContactEmailVerified() ) { return ResponseEntity.badRequest().body( "Contact email is already verified." ); } @@ -380,7 +379,7 @@ public static BindingResultModel fromBindingResult( BindingResult bindingResult @ResponseBody @PostMapping(value = "/user/profile", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity saveProfile( @Valid @RequestBody ProfileWithOrganUberonIdsAndOntologyTerms profileWithOrganUberonIdsAndOntologyTerms, BindingResult bindingResult, Locale locale ) { - User user = userService.findCurrentUser(); + User user = requireNonNull( userService.findCurrentUser() ); if ( bindingResult.hasErrors() ) { return ResponseEntity.badRequest() .body( BindingResultModel.fromBindingResult( bindingResult ) ); @@ -400,31 +399,31 @@ public ResponseEntity saveProfile( @Valid @RequestBody ProfileWithOrganUberon @ResponseBody @GetMapping(value = "/user", produces = MediaType.APPLICATION_JSON_VALUE) public User getUser() { - return userService.findCurrentUser(); + return requireNonNull( userService.findCurrentUser() ); } @ResponseBody @GetMapping(value = "/user/taxon", produces = MediaType.APPLICATION_JSON_VALUE) public Set getTaxons() { - return userService.findCurrentUser().getUserGenes().values().stream().map( UserGene::getTaxon ).collect( Collectors.toSet() ); + return requireNonNull( userService.findCurrentUser() ).getUserGenes().values().stream().map( UserGene::getTaxon ).collect( Collectors.toSet() ); } @ResponseBody @GetMapping(value = "/user/gene", produces = MediaType.APPLICATION_JSON_VALUE) public Collection getGenes() { - return userService.findCurrentUser().getUserGenes().values(); + return requireNonNull( userService.findCurrentUser() ).getUserGenes().values(); } @ResponseBody @GetMapping(value = "/user/term", produces = MediaType.APPLICATION_JSON_VALUE) public Collection getTerms() { - return userService.findCurrentUser().getUserTerms(); + return requireNonNull( userService.findCurrentUser() ).getUserTerms(); } @ResponseBody @GetMapping(value = "/user/ontology-terms", produces = MediaType.APPLICATION_JSON_VALUE) public Collection getOntologyTerms() { - return userService.findCurrentUser().getUserOntologyTerms(); + return requireNonNull( userService.findCurrentUser() ).getUserOntologyTerms(); } @Data @@ -438,7 +437,7 @@ public static class Model { @ResponseBody @PostMapping(value = "/user/model/{taxonId}", produces = MediaType.TEXT_PLAIN_VALUE) public Object saveModelForTaxon( @PathVariable Integer taxonId, @RequestBody Model model ) { - User user = userService.findCurrentUser(); + User user = requireNonNull( userService.findCurrentUser() ); Taxon taxon = taxonService.findById( taxonId ); if ( taxon == null ) { @@ -476,7 +475,7 @@ public Object getGenesForTaxon( @PathVariable Integer taxonId ) { if ( taxon == null ) { return ResponseEntity.notFound().build(); } - return userService.findCurrentUser().getGenesByTaxon( taxon ); + return requireNonNull( userService.findCurrentUser() ).getGenesByTaxon( taxon ); } @ResponseBody @@ -486,7 +485,7 @@ public Object getTermsForTaxon( @PathVariable Integer taxonId ) { if ( taxon == null ) { return ResponseEntity.notFound().build(); } - return userService.findCurrentUser().getTermsByTaxon( taxon ); + return requireNonNull( userService.findCurrentUser() ).getTermsByTaxon( taxon ); } @ResponseBody @@ -497,8 +496,11 @@ public Object getTermsForTaxon( @PathVariable Integer taxonId, if ( taxon == null ) { return ResponseEntity.notFound().build(); } - User user = userService.findCurrentUser(); - return goIds.stream().collect( toNullableMap( identity(), goId -> goService.getTerm( goId ) == null ? null : userService.convertTerm( user, taxon, goService.getTerm( goId ) ) ) ); + User user = requireNonNull( userService.findCurrentUser() ); + return goIds.stream().collect( toNullableMap( identity(), goId -> { + GeneOntologyTermInfo term = goService.getTerm( goId ); + return term == null ? null : userService.convertTerm( user, taxon, term ); + } ) ); } @Value @@ -517,14 +519,14 @@ static class RecommendedTermsModel { @ResponseBody @GetMapping(value = "/user/taxon/{taxonId}/term/recommend", produces = MediaType.APPLICATION_JSON_VALUE) public Object getRecommendedTermsForTaxon( @PathVariable Integer taxonId, - @RequestParam(required = false) List geneIds, + @RequestParam(required = false) @Nullable List geneIds, Locale locale ) { Taxon taxon = taxonService.findById( taxonId ); if ( taxon == null ) { return ResponseEntity.notFound().build(); } - User user = userService.findCurrentUser(); + User user = requireNonNull( userService.findCurrentUser() ); Collection recommendedTerms; List feedback = new ArrayList<>(); diff --git a/src/main/java/ubc/pavlab/rdp/controllers/package-info.java b/src/main/java/ubc/pavlab/rdp/controllers/package-info.java new file mode 100644 index 00000000..fdd0823f --- /dev/null +++ b/src/main/java/ubc/pavlab/rdp/controllers/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +@NonNullApi +package ubc.pavlab.rdp.controllers; + +import org.springframework.lang.NonNullApi; \ No newline at end of file diff --git a/src/main/java/ubc/pavlab/rdp/events/package-info.java b/src/main/java/ubc/pavlab/rdp/events/package-info.java new file mode 100644 index 00000000..1bd481ed --- /dev/null +++ b/src/main/java/ubc/pavlab/rdp/events/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +@NonNullApi +package ubc.pavlab.rdp.events; + +import org.springframework.lang.NonNullApi; \ No newline at end of file diff --git a/src/main/java/ubc/pavlab/rdp/exception/package-info.java b/src/main/java/ubc/pavlab/rdp/exception/package-info.java new file mode 100644 index 00000000..782619c2 --- /dev/null +++ b/src/main/java/ubc/pavlab/rdp/exception/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +@NonNullApi +package ubc.pavlab.rdp.exception; + +import org.springframework.lang.NonNullApi; \ No newline at end of file diff --git a/src/main/java/ubc/pavlab/rdp/listeners/package-info.java b/src/main/java/ubc/pavlab/rdp/listeners/package-info.java new file mode 100644 index 00000000..e6d1470b --- /dev/null +++ b/src/main/java/ubc/pavlab/rdp/listeners/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +@NonNullApi +package ubc.pavlab.rdp.listeners; + +import org.springframework.lang.NonNullApi; \ No newline at end of file diff --git a/src/main/java/ubc/pavlab/rdp/model/User.java b/src/main/java/ubc/pavlab/rdp/model/User.java index ea6ec23c..7639a7b4 100644 --- a/src/main/java/ubc/pavlab/rdp/model/User.java +++ b/src/main/java/ubc/pavlab/rdp/model/User.java @@ -11,6 +11,7 @@ import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; +import org.springframework.lang.Nullable; import ubc.pavlab.rdp.model.enums.PrivacyLevelType; import ubc.pavlab.rdp.model.enums.TierType; import ubc.pavlab.rdp.model.ontology.Ontology; @@ -205,7 +206,7 @@ public Set getTermsByTaxon( Taxon taxon ) { @JsonIgnore @Transient - public boolean hasTaxon( @NonNull Taxon taxon ) { + public boolean hasTaxon( Taxon taxon ) { return this.getUserGenes().values().stream().anyMatch( g -> g.getTaxon().equals( taxon ) ); } @@ -241,6 +242,7 @@ public Optional getVerifiedContactEmail() { /** * This is meant for JSON serialization of the user's public-facing email. */ + @Nullable @JsonProperty("email") public String getVerifiedContactEmailJsonValue() { if ( profile != null && profile.isContactEmailVerified() ) { diff --git a/src/main/java/ubc/pavlab/rdp/model/UserContent.java b/src/main/java/ubc/pavlab/rdp/model/UserContent.java index bfca3e0a..0a22ec57 100644 --- a/src/main/java/ubc/pavlab/rdp/model/UserContent.java +++ b/src/main/java/ubc/pavlab/rdp/model/UserContent.java @@ -1,6 +1,6 @@ package ubc.pavlab.rdp.model; -import lombok.NonNull; +import org.springframework.lang.NonNull; import ubc.pavlab.rdp.model.enums.PrivacyLevelType; import java.time.Instant; @@ -22,7 +22,6 @@ public interface UserContent { * In many cases, content have intrinsic privacy level that might be undefined; the implementation has to perform * cascading generally by using the owner privacy level. */ - @NonNull PrivacyLevelType getEffectivePrivacyLevel(); /** diff --git a/src/main/java/ubc/pavlab/rdp/model/UserGene.java b/src/main/java/ubc/pavlab/rdp/model/UserGene.java index 3b8e40dc..a5290d1c 100644 --- a/src/main/java/ubc/pavlab/rdp/model/UserGene.java +++ b/src/main/java/ubc/pavlab/rdp/model/UserGene.java @@ -20,7 +20,6 @@ import java.util.Comparator; import java.util.Optional; import java.util.UUID; -import java.io.Serializable; /** * Created by mjacobson on 17/01/18. @@ -91,6 +90,7 @@ public static Comparator getComparator() { @Transient private User remoteUser; + @Nullable @Column(name = "user_privacy_level") @ColumnDefault("NULL") @Enumerated(EnumType.ORDINAL) @@ -153,7 +153,7 @@ public PrivacyLevelType getEffectivePrivacyLevel() { } @JsonProperty("privacyLevel") - public void setPrivacyLevel( PrivacyLevelType privacyLevel ) { + public void setPrivacyLevel( @Nullable PrivacyLevelType privacyLevel ) { this.privacyLevel = privacyLevel; } diff --git a/src/main/java/ubc/pavlab/rdp/model/ontology/Ontology.java b/src/main/java/ubc/pavlab/rdp/model/ontology/Ontology.java index 4d6e0487..a769898f 100644 --- a/src/main/java/ubc/pavlab/rdp/model/ontology/Ontology.java +++ b/src/main/java/ubc/pavlab/rdp/model/ontology/Ontology.java @@ -39,7 +39,7 @@ public class Ontology implements Comparable { */ public static final int MAX_NAME_LENGTH = 255; - public static OntologyBuilder builder( @NonNull String name ) { + public static OntologyBuilder builder( String name ) { return new OntologyBuilderImpl().name( name ); } diff --git a/src/main/java/ubc/pavlab/rdp/model/ontology/OntologyTermInfo.java b/src/main/java/ubc/pavlab/rdp/model/ontology/OntologyTermInfo.java index 71075b7f..73ae4f81 100644 --- a/src/main/java/ubc/pavlab/rdp/model/ontology/OntologyTermInfo.java +++ b/src/main/java/ubc/pavlab/rdp/model/ontology/OntologyTermInfo.java @@ -51,7 +51,7 @@ public class OntologyTermInfo extends OntologyTerm implements Comparable builder( @NonNull Ontology ontology, @NonNull String termId ) { + public static OntologyTermInfoBuilder builder( Ontology ontology, String termId ) { return new OntologyTermInfo.OntologyTermInfoBuilderImpl() .ontology( ontology ) .termId( termId ); diff --git a/src/main/java/ubc/pavlab/rdp/model/ontology/RemoteOntology.java b/src/main/java/ubc/pavlab/rdp/model/ontology/RemoteOntology.java index 6bda4ba7..0b7ec702 100644 --- a/src/main/java/ubc/pavlab/rdp/model/ontology/RemoteOntology.java +++ b/src/main/java/ubc/pavlab/rdp/model/ontology/RemoteOntology.java @@ -1,6 +1,9 @@ package ubc.pavlab.rdp.model.ontology; -import lombok.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; import lombok.experimental.SuperBuilder; import ubc.pavlab.rdp.model.RemoteResource; @@ -16,7 +19,7 @@ @ToString(of = { "origin", "originUrl" }, callSuper = true) public class RemoteOntology extends Ontology implements RemoteResource { - public static RemoteOntologyBuilder builder( @NonNull String name ) { + public static RemoteOntologyBuilder builder( String name ) { return new RemoteOntologyBuilderImpl().name( name ); } diff --git a/src/main/java/ubc/pavlab/rdp/model/ontology/UserOntologyTerm.java b/src/main/java/ubc/pavlab/rdp/model/ontology/UserOntologyTerm.java index 8e886452..6d99c148 100644 --- a/src/main/java/ubc/pavlab/rdp/model/ontology/UserOntologyTerm.java +++ b/src/main/java/ubc/pavlab/rdp/model/ontology/UserOntologyTerm.java @@ -4,7 +4,6 @@ import lombok.*; import lombok.experimental.SuperBuilder; import org.hibernate.annotations.NaturalId; -import org.springframework.context.MessageSourceResolvable; import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; @@ -93,7 +92,7 @@ public Optional getOwner() { @Override @JsonIgnore - public @NonNull PrivacyLevelType getEffectivePrivacyLevel() { + public PrivacyLevelType getEffectivePrivacyLevel() { return user.getEffectivePrivacyLevel(); } diff --git a/src/main/java/ubc/pavlab/rdp/model/package-info.java b/src/main/java/ubc/pavlab/rdp/model/package-info.java new file mode 100644 index 00000000..a5d66572 --- /dev/null +++ b/src/main/java/ubc/pavlab/rdp/model/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +@NonNullApi +package ubc.pavlab.rdp.model; + +import org.springframework.lang.NonNullApi; \ No newline at end of file diff --git a/src/main/java/ubc/pavlab/rdp/ontology/resolvers/OntologyResolver.java b/src/main/java/ubc/pavlab/rdp/ontology/resolvers/OntologyResolver.java index 7087a4e9..44b81d6b 100644 --- a/src/main/java/ubc/pavlab/rdp/ontology/resolvers/OntologyResolver.java +++ b/src/main/java/ubc/pavlab/rdp/ontology/resolvers/OntologyResolver.java @@ -1,5 +1,6 @@ package ubc.pavlab.rdp.ontology.resolvers; +import org.springframework.lang.Nullable; import ubc.pavlab.rdp.model.ontology.Ontology; import ubc.pavlab.rdp.model.ontology.OntologyTerm; @@ -18,10 +19,12 @@ public interface OntologyResolver { /** * Retrieve a URI for an ontology. */ + @Nullable URI resolveViewOntologyUrl( Ontology ontology ); /** * Retrieve a URI for a term. */ + @Nullable URI resolveViewTermUrl( OntologyTerm term ); } diff --git a/src/main/java/ubc/pavlab/rdp/ontology/resolvers/package-info.java b/src/main/java/ubc/pavlab/rdp/ontology/resolvers/package-info.java new file mode 100644 index 00000000..b2fb86ee --- /dev/null +++ b/src/main/java/ubc/pavlab/rdp/ontology/resolvers/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +@NonNullApi +package ubc.pavlab.rdp.ontology.resolvers; + +import org.springframework.lang.NonNullApi; \ No newline at end of file diff --git a/src/main/java/ubc/pavlab/rdp/package-info.java b/src/main/java/ubc/pavlab/rdp/package-info.java new file mode 100644 index 00000000..ae631db9 --- /dev/null +++ b/src/main/java/ubc/pavlab/rdp/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +@NonNullApi +package ubc.pavlab.rdp; + +import org.springframework.lang.NonNullApi; \ No newline at end of file diff --git a/src/main/java/ubc/pavlab/rdp/repositories/GeneInfoRepository.java b/src/main/java/ubc/pavlab/rdp/repositories/GeneInfoRepository.java index dad478c8..cff84890 100644 --- a/src/main/java/ubc/pavlab/rdp/repositories/GeneInfoRepository.java +++ b/src/main/java/ubc/pavlab/rdp/repositories/GeneInfoRepository.java @@ -3,6 +3,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import org.springframework.lang.Nullable; import org.springframework.stereotype.Repository; import ubc.pavlab.rdp.model.GeneInfo; import ubc.pavlab.rdp.model.Taxon; @@ -12,6 +13,7 @@ @Repository public interface GeneInfoRepository extends JpaRepository { + @Nullable GeneInfo findByGeneId( Integer geneId ); Collection findAllByGeneIdIn( Collection geneIds ); @@ -19,8 +21,10 @@ public interface GeneInfoRepository extends JpaRepository { @Query("select gene from GeneInfo gene left join fetch gene.orthologs where gene.geneId in :geneIds") Collection findAllByGeneIdWithOrthologs( @Param("geneIds") Collection geneIds ); + @Nullable GeneInfo findByGeneIdAndTaxon( Integer geneId, Taxon taxon ); + @Nullable GeneInfo findBySymbolAndTaxon( String symbol, Taxon taxon ); Collection findBySymbolInAndTaxon( Collection symbols, Taxon taxon ); diff --git a/src/main/java/ubc/pavlab/rdp/repositories/PasswordResetTokenRepository.java b/src/main/java/ubc/pavlab/rdp/repositories/PasswordResetTokenRepository.java index c98abd9c..87c2320b 100644 --- a/src/main/java/ubc/pavlab/rdp/repositories/PasswordResetTokenRepository.java +++ b/src/main/java/ubc/pavlab/rdp/repositories/PasswordResetTokenRepository.java @@ -3,6 +3,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; +import org.springframework.lang.Nullable; import org.springframework.stereotype.Repository; import ubc.pavlab.rdp.model.PasswordResetToken; @@ -10,6 +11,7 @@ @Repository public interface PasswordResetTokenRepository extends JpaRepository { + @Nullable PasswordResetToken findByToken( String token ); @Modifying diff --git a/src/main/java/ubc/pavlab/rdp/repositories/RoleRepository.java b/src/main/java/ubc/pavlab/rdp/repositories/RoleRepository.java index 08755dde..751a6094 100644 --- a/src/main/java/ubc/pavlab/rdp/repositories/RoleRepository.java +++ b/src/main/java/ubc/pavlab/rdp/repositories/RoleRepository.java @@ -1,6 +1,7 @@ package ubc.pavlab.rdp.repositories; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.lang.Nullable; import org.springframework.stereotype.Repository; import ubc.pavlab.rdp.model.Role; @@ -9,6 +10,7 @@ */ @Repository public interface RoleRepository extends JpaRepository { + @Nullable Role findByRole( String role ); } \ No newline at end of file diff --git a/src/main/java/ubc/pavlab/rdp/repositories/UserGeneRepository.java b/src/main/java/ubc/pavlab/rdp/repositories/UserGeneRepository.java index e3789d03..f1b6e5e2 100644 --- a/src/main/java/ubc/pavlab/rdp/repositories/UserGeneRepository.java +++ b/src/main/java/ubc/pavlab/rdp/repositories/UserGeneRepository.java @@ -6,6 +6,7 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.QueryHints; import org.springframework.data.repository.query.Param; +import org.springframework.lang.Nullable; import org.springframework.stereotype.Repository; import ubc.pavlab.rdp.model.Taxon; import ubc.pavlab.rdp.model.UserGene; @@ -43,7 +44,7 @@ public interface UserGeneRepository extends JpaRepository { /** * Find all genes from enabled users. */ - Page findByUserEnabledTrue( Pageable pageable ); + Page findByUserEnabledTrue( @Nullable Pageable pageable ); /** * Find all user genes that fall within a given privacy level amonng enabled users. @@ -51,7 +52,7 @@ public interface UserGeneRepository extends JpaRepository { * If the user gene privacy level is less strict than the profile value or null, then the profile value is taken. */ @Query("select ug from UserGene as ug join ug.user where ug.user.enabled is true and (case when ug.privacyLevel is null or ug.privacyLevel > ug.user.profile.privacyLevel then ug.user.profile.privacyLevel else ug.privacyLevel end) = :privacyLevel") - Page findByPrivacyLevelAndUserEnabledTrueAndUserProfilePrivacyLevel( @Param("privacyLevel") PrivacyLevelType privacyLevel, Pageable pageable ); + Page findByPrivacyLevelAndUserEnabledTrueAndUserProfilePrivacyLevel( @Param("privacyLevel") PrivacyLevelType privacyLevel, @Nullable Pageable pageable ); @QueryHints(@QueryHint(name = "org.hibernate.cacheable", value = "true")) UserGene findById( int id ); diff --git a/src/main/java/ubc/pavlab/rdp/repositories/VerificationTokenRepository.java b/src/main/java/ubc/pavlab/rdp/repositories/VerificationTokenRepository.java index 3a0a1c67..be0210e9 100644 --- a/src/main/java/ubc/pavlab/rdp/repositories/VerificationTokenRepository.java +++ b/src/main/java/ubc/pavlab/rdp/repositories/VerificationTokenRepository.java @@ -3,6 +3,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; +import org.springframework.lang.Nullable; import org.springframework.stereotype.Repository; import ubc.pavlab.rdp.model.VerificationToken; @@ -10,6 +11,7 @@ @Repository public interface VerificationTokenRepository extends JpaRepository { + @Nullable VerificationToken findByToken( String token ); @Modifying diff --git a/src/main/java/ubc/pavlab/rdp/repositories/package-info.java b/src/main/java/ubc/pavlab/rdp/repositories/package-info.java new file mode 100644 index 00000000..91baf825 --- /dev/null +++ b/src/main/java/ubc/pavlab/rdp/repositories/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +@NonNullApi +package ubc.pavlab.rdp.repositories; + +import org.springframework.lang.NonNullApi; \ No newline at end of file diff --git a/src/main/java/ubc/pavlab/rdp/security/authentication/TokenBasedAuthentication.java b/src/main/java/ubc/pavlab/rdp/security/authentication/TokenBasedAuthentication.java index 6fa7ba1b..02cc32a6 100644 --- a/src/main/java/ubc/pavlab/rdp/security/authentication/TokenBasedAuthentication.java +++ b/src/main/java/ubc/pavlab/rdp/security/authentication/TokenBasedAuthentication.java @@ -1,5 +1,6 @@ package ubc.pavlab.rdp.security.authentication; +import org.springframework.lang.Nullable; import org.springframework.security.authentication.AbstractAuthenticationToken; public class TokenBasedAuthentication extends AbstractAuthenticationToken { @@ -17,6 +18,7 @@ public Object getCredentials() { } @Override + @Nullable public Object getPrincipal() { return null; } diff --git a/src/main/java/ubc/pavlab/rdp/security/authentication/TokenBasedAuthenticationConverter.java b/src/main/java/ubc/pavlab/rdp/security/authentication/TokenBasedAuthenticationConverter.java index 19086cc7..816b2678 100644 --- a/src/main/java/ubc/pavlab/rdp/security/authentication/TokenBasedAuthenticationConverter.java +++ b/src/main/java/ubc/pavlab/rdp/security/authentication/TokenBasedAuthenticationConverter.java @@ -1,5 +1,6 @@ package ubc.pavlab.rdp.security.authentication; +import org.springframework.lang.Nullable; import org.springframework.security.web.authentication.AuthenticationConverter; import javax.servlet.http.HttpServletRequest; @@ -12,6 +13,7 @@ */ class TokenBasedAuthenticationConverter implements AuthenticationConverter { + @Nullable @Override public final TokenBasedAuthentication convert( HttpServletRequest request ) throws IllegalArgumentException { String authorizationHeader = request.getHeader( "Authorization" ); diff --git a/src/main/java/ubc/pavlab/rdp/security/authentication/package-info.java b/src/main/java/ubc/pavlab/rdp/security/authentication/package-info.java new file mode 100644 index 00000000..eca00c47 --- /dev/null +++ b/src/main/java/ubc/pavlab/rdp/security/authentication/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +@NonNullApi +package ubc.pavlab.rdp.security.authentication; + +import org.springframework.lang.NonNullApi; \ No newline at end of file diff --git a/src/main/java/ubc/pavlab/rdp/security/package-info.java b/src/main/java/ubc/pavlab/rdp/security/package-info.java new file mode 100644 index 00000000..48c804bb --- /dev/null +++ b/src/main/java/ubc/pavlab/rdp/security/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +@NonNullApi +package ubc.pavlab.rdp.security; + +import org.springframework.lang.NonNullApi; \ No newline at end of file diff --git a/src/main/java/ubc/pavlab/rdp/services/EmailService.java b/src/main/java/ubc/pavlab/rdp/services/EmailService.java index 16ffb1b6..00eb00c0 100644 --- a/src/main/java/ubc/pavlab/rdp/services/EmailService.java +++ b/src/main/java/ubc/pavlab/rdp/services/EmailService.java @@ -1,5 +1,6 @@ package ubc.pavlab.rdp.services; +import org.springframework.lang.Nullable; import org.springframework.web.multipart.MultipartFile; import ubc.pavlab.rdp.model.PasswordResetToken; import ubc.pavlab.rdp.model.User; @@ -15,7 +16,7 @@ */ public interface EmailService { - Future sendSupportMessage( String message, String name, User user, String userAgent, MultipartFile attachment, Locale locale ) throws MessagingException; + Future sendSupportMessage( String message, String name, User user, String userAgent, @Nullable MultipartFile attachment, Locale locale ) throws MessagingException; Future sendResetTokenMessage( User user, PasswordResetToken token, Locale locale ) throws MessagingException; diff --git a/src/main/java/ubc/pavlab/rdp/services/EmailServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/EmailServiceImpl.java index 13776495..4ea4ae4d 100644 --- a/src/main/java/ubc/pavlab/rdp/services/EmailServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/EmailServiceImpl.java @@ -5,7 +5,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.MessageSource; import org.springframework.core.task.AsyncTaskExecutor; -import org.springframework.core.task.TaskExecutor; +import org.springframework.lang.Nullable; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; @@ -31,7 +31,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Locale; -import java.util.concurrent.*; +import java.util.concurrent.Future; /** * Created by mjacobson on 19/01/18. @@ -53,7 +53,7 @@ public class EmailServiceImpl implements EmailService { @Qualifier("emailTaskExecutor") private AsyncTaskExecutor executorService; - private Future sendSimpleMessage( String subject, String content, InternetAddress to, InternetAddress replyTo, InternetAddress cc ) throws AddressException { + private Future sendSimpleMessage( String subject, String content, InternetAddress to, @Nullable InternetAddress replyTo, @Nullable InternetAddress cc ) throws AddressException { SimpleMailMessage email = new SimpleMailMessage(); email.setSubject( subject ); @@ -70,7 +70,7 @@ private Future sendSimpleMessage( String subject, String content, InternetAdd return executorService.submit( () -> emailSender.send( email ) ); } - private Future sendMultipartMessage( String subject, String content, InternetAddress to, InternetAddress replyTo, MultipartFile attachment ) throws MessagingException { + private Future sendMultipartMessage( String subject, String content, InternetAddress to, @Nullable InternetAddress replyTo, MultipartFile attachment ) throws MessagingException { MimeMessage message = emailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper( message, true ); @@ -92,7 +92,7 @@ private Future sendMultipartMessage( String subject, String content, Internet } @Override - public Future sendSupportMessage( String message, String name, User user, String userAgent, MultipartFile attachment, Locale locale ) throws MessagingException { + public Future sendSupportMessage( String message, String name, User user, String userAgent, @Nullable MultipartFile attachment, Locale locale ) throws MessagingException { InternetAddress replyTo = user.getVerifiedContactEmail().orElseThrow( () -> new MessagingException( "Could not find a verified email address for user." ) ); String subject = messageSource.getMessage( "EmailService.sendSupportMessage.subject", new Object[]{ Messages.SHORTNAME }, locale ); String content = "Name: " + name + "\r\n" + diff --git a/src/main/java/ubc/pavlab/rdp/services/GOService.java b/src/main/java/ubc/pavlab/rdp/services/GOService.java index 3e60fce5..64388c48 100644 --- a/src/main/java/ubc/pavlab/rdp/services/GOService.java +++ b/src/main/java/ubc/pavlab/rdp/services/GOService.java @@ -1,6 +1,9 @@ package ubc.pavlab.rdp.services; -import ubc.pavlab.rdp.model.*; +import org.springframework.lang.Nullable; +import ubc.pavlab.rdp.model.Gene; +import ubc.pavlab.rdp.model.GeneOntologyTermInfo; +import ubc.pavlab.rdp.model.Taxon; import ubc.pavlab.rdp.util.SearchResult; import java.util.Collection; @@ -48,6 +51,7 @@ public interface GOService { Collection getGenesInTaxon( Collection goTerms, Taxon taxon ); + @Nullable GeneOntologyTermInfo getTerm( String goId ); Collection getTermsForGene( Gene gene ); diff --git a/src/main/java/ubc/pavlab/rdp/services/GOServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/GOServiceImpl.java index 34803cd7..7352a58d 100644 --- a/src/main/java/ubc/pavlab/rdp/services/GOServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/GOServiceImpl.java @@ -8,6 +8,7 @@ import org.springframework.cache.CacheManager; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; +import org.springframework.lang.Nullable; import org.springframework.stereotype.Service; import ubc.pavlab.rdp.model.Gene; import ubc.pavlab.rdp.model.GeneOntologyTermInfo; @@ -209,6 +210,7 @@ public Map termFrequencyMap( Collection queryTerm( String queryString, GeneOntologyTermInfo term ) { if ( term.getGoId().equalsIgnoreCase( queryString ) || term.getGoId().equalsIgnoreCase( "GO:" + queryString ) ) { return new SearchResult<>( TermMatchType.EXACT_ID, 0, term.getGoId(), term.getName(), term ); @@ -415,17 +417,14 @@ public Collection getDirectGenes( GeneOntologyTermInfo term ) { } @Override - public Collection getGenesInTaxon( String id, Taxon taxon ) { - if ( id == null ) { - return Collections.emptySet(); - } + public Collection getGenesInTaxon( String id, Taxon taxon ) { return goRepository.findById( id ) .map( term -> getGenesInTaxon( term, taxon ) ) .orElseGet( Collections::emptySet ); } @Override - public Collection getGenesInTaxon( GeneOntologyTermInfo t, Taxon taxon ) { + public Collection getGenesInTaxon( GeneOntologyTermInfo t, Taxon taxon ) { Collection descendants = new HashSet<>( getDescendants( t ) ); descendants.add( t ); @@ -453,9 +452,6 @@ public Collection getGenesInTaxon( Collection goT @Override public GeneOntologyTermInfo getTerm( String goId ) { - if ( goId == null ) { - return null; - } return goRepository.findById( goId ).orElse( null ); } diff --git a/src/main/java/ubc/pavlab/rdp/services/GeneInfoService.java b/src/main/java/ubc/pavlab/rdp/services/GeneInfoService.java index a3fd9266..a48ee0ba 100644 --- a/src/main/java/ubc/pavlab/rdp/services/GeneInfoService.java +++ b/src/main/java/ubc/pavlab/rdp/services/GeneInfoService.java @@ -19,6 +19,7 @@ package ubc.pavlab.rdp.services; +import org.springframework.lang.Nullable; import ubc.pavlab.rdp.model.GeneInfo; import ubc.pavlab.rdp.model.Taxon; import ubc.pavlab.rdp.util.SearchResult; @@ -30,10 +31,12 @@ */ public interface GeneInfoService { + @Nullable GeneInfo load( Integer geneId ); Collection load( Collection ids ); + @Nullable GeneInfo findBySymbolAndTaxon( String officialSymbol, Taxon taxon ); Collection findBySymbolInAndTaxon( Collection symbols, Taxon taxon ); diff --git a/src/main/java/ubc/pavlab/rdp/services/OntologyService.java b/src/main/java/ubc/pavlab/rdp/services/OntologyService.java index 4eaead12..cab5fab5 100644 --- a/src/main/java/ubc/pavlab/rdp/services/OntologyService.java +++ b/src/main/java/ubc/pavlab/rdp/services/OntologyService.java @@ -19,6 +19,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.util.Pair; +import org.springframework.lang.Nullable; import org.springframework.security.access.annotation.Secured; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -106,14 +107,17 @@ private boolean isFullTextSupported() { return HibernateUtils.getDialect( entityManager ) instanceof MySQLDialect; } + @Nullable public Ontology findById( Integer id ) { return ontologyRepository.findById( id ).orElse( null ); } + @Nullable public Ontology findByName( String name ) { return ontologyRepository.findByName( name ); } + @Nullable public Ontology findByNameAndActiveTrue( String name ) { return ontologyRepository.findByNameAndActiveTrue( name ); } @@ -625,6 +629,7 @@ public void saveTermsNoAuth( Iterable terms ) { ontologyTermInfoRepository.saveAll( terms ); } + @Nullable @Transactional(readOnly = true) public OntologyTermInfo findTermByTermIdAndOntologyName( String termId, String ontologyName ) { return ontologyTermInfoRepository.findByTermIdAndOntologyName( termId, ontologyName ); @@ -835,6 +840,7 @@ private List> autocompleteTerms( String query, Se return new ArrayList<>( sortedResults ); } + @Nullable private String getTermDefinition( OntologyTermInfo term, Locale locale ) { try { return messageSource.getMessage( term.getResolvableDefinition(), locale ); @@ -882,7 +888,7 @@ public long subtreeSize( OntologyTermInfo term ) { return getDescendentIds( Collections.singleton( term ) ).size(); } - private SearchResult toSearchResult( OntologyTermInfo t, OntologyTermMatchType matchType, String extras, double tfIdf, Locale locale ) { + private SearchResult toSearchResult( OntologyTermInfo t, OntologyTermMatchType matchType, @Nullable String extras, double tfIdf, Locale locale ) { SearchResult result = new SearchResult<>( matchType, t.getId(), @@ -908,6 +914,7 @@ private Comparator> getSearchResultComparator( Li .thenComparing( SearchResult::getMatch, getTopologicalComparator( foundTerms, similarityByMatch, maxResults ) ); } + @Nullable public OntologyTermInfo findTermById( Integer ontologyTermId ) { return ontologyTermInfoRepository.findById( ontologyTermId ).orElse( null ); } diff --git a/src/main/java/ubc/pavlab/rdp/services/OrganInfoServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/OrganInfoServiceImpl.java index 261c3178..c2ba8fb5 100644 --- a/src/main/java/ubc/pavlab/rdp/services/OrganInfoServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/OrganInfoServiceImpl.java @@ -56,11 +56,10 @@ public Collection findByActiveTrueOrderByOrdering() { @Override @Transactional public void updateOrganInfos() { - Resource organFile = null; - if ( applicationSettings.getCache().getOrganFile() != null || applicationSettings.getCache().getOrganFile().isEmpty() ) { + Resource organFile; + if ( applicationSettings.getCache().getOrganFile() != null && !applicationSettings.getCache().getOrganFile().isEmpty() ) { organFile = resourceLoader.getResource( applicationSettings.getCache().getOrganFile() ); - } - if ( organFile == null ) { + } else { log.warn( "No organ system ontology file found, skipping update." ); return; } @@ -75,7 +74,7 @@ public void updateOrganInfos() { Map organInfosByUberonId = organInfoRepository.findAll().stream() .collect( Collectors.toMap( OrganInfo::getUberonId, identity() ) ); for ( OBOParser.Term term : parsedTerms ) { - OrganInfo organInfo = organInfosByUberonId.get(term.getId()); + OrganInfo organInfo = organInfosByUberonId.get( term.getId() ); if ( organInfo == null ) { organInfo = new OrganInfo(); organInfo.setUberonId( term.getId() ); diff --git a/src/main/java/ubc/pavlab/rdp/services/ReactomeService.java b/src/main/java/ubc/pavlab/rdp/services/ReactomeService.java index b0cbc38b..7e7b29df 100644 --- a/src/main/java/ubc/pavlab/rdp/services/ReactomeService.java +++ b/src/main/java/ubc/pavlab/rdp/services/ReactomeService.java @@ -12,6 +12,7 @@ import org.springframework.data.domain.PageRequest; import org.springframework.http.HttpEntity; import org.springframework.http.ResponseEntity; +import org.springframework.lang.Nullable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.client.RestTemplate; @@ -54,6 +55,7 @@ public ReactomeService( OntologyService ontologyService, ApplicationSettings app /** * @return */ + @Nullable public Ontology findPathwaysOntology() { return ontologyService.findByName( applicationSettings.getOntology().getReactomePathwaysOntologyName() ); } @@ -83,6 +85,7 @@ public Ontology importPathwaysOntology() throws ReactomeException { * @throws ReactomeException if any operation with the data files fail, in which case the whole transaction will be * rolled back. */ + @Nullable @Transactional(rollbackFor = ReactomeException.class) public Ontology updatePathwaysOntology() throws ReactomeException { if ( ontologyService.existsByName( applicationSettings.getOntology().getReactomePathwaysOntologyName() ) ) { @@ -176,7 +179,7 @@ private Ontology importOrUpdatePathwaysOntology() throws ReactomeException { * transaction will be rolled back. */ @Transactional(rollbackFor = ReactomeException.class) - public void updatePathwaySummations( ProgressCallback progressCallback ) throws ReactomeException { + public void updatePathwaySummations( @Nullable ProgressCallback progressCallback ) throws ReactomeException { String ontologyName = applicationSettings.getOntology().getReactomePathwaysOntologyName(); Ontology ontology = ontologyService.findByName( ontologyName ); if ( ontology == null ) { diff --git a/src/main/java/ubc/pavlab/rdp/services/RemoteResourceService.java b/src/main/java/ubc/pavlab/rdp/services/RemoteResourceService.java index c9827a35..4a58fc73 100644 --- a/src/main/java/ubc/pavlab/rdp/services/RemoteResourceService.java +++ b/src/main/java/ubc/pavlab/rdp/services/RemoteResourceService.java @@ -1,5 +1,6 @@ package ubc.pavlab.rdp.services; +import org.springframework.lang.Nullable; import ubc.pavlab.rdp.controllers.ApiController; import ubc.pavlab.rdp.exception.RemoteException; import ubc.pavlab.rdp.exception.UnknownRemoteApiException; @@ -62,7 +63,7 @@ public interface RemoteResourceService { * @return matching users sorted according to {@link User#getComparator()}. * @see ApiController#searchUsersByName(String, Boolean, Set, Set, Set, List, List, Locale) */ - List findUsersByLikeName( String nameLike, Boolean prefix, Set researcherPositions, Collection researcherTypes, Collection organUberonIds, Map> ontologyTermInfos ); + List findUsersByLikeName( String nameLike, Boolean prefix, @Nullable Set researcherPositions, @Nullable Collection researcherTypes, @Nullable Collection organUberonIds, @Nullable Map> ontologyTermInfos ); /** * Find users by description among all partner registries. @@ -70,9 +71,9 @@ public interface RemoteResourceService { * @return matching users sorted according to {@link User#getComparator()}. * @see ApiController#searchUsersByDescription(String, Set, Set, Set, List, List, Locale) */ - List findUsersByDescription( String descriptionLike, Set researcherPositions, Collection researcherTypes, Collection organUberonIds, Map> ontologyTermInfos ); + List findUsersByDescription( String descriptionLike, @Nullable Set researcherPositions, @Nullable Collection researcherTypes, @Nullable Collection organUberonIds, @Nullable Map> ontologyTermInfos ); - List findUsersByLikeNameAndDescription( String nameLike, boolean prefix, String descriptionLike, Set researcherPositions, Set researcherCategories, Set organUberonIds, Map> ontologyTermInfos ); + List findUsersByLikeNameAndDescription( String nameLike, boolean prefix, String descriptionLike, @Nullable Set researcherPositions, @Nullable Set researcherCategories, @Nullable Set organUberonIds, @Nullable Map> ontologyTermInfos ); /** * Find genes by symbol among all partner registries. @@ -80,7 +81,7 @@ public interface RemoteResourceService { * @return matching genes sorted according to {@link UserGene#getComparator()}. * @see ApiController#searchUsersByGeneSymbol(String, Integer, Set, Integer, Set, Set, Set, List, List, Locale) */ - List findGenesBySymbol( String symbol, Taxon taxon, Set tier, Integer orthologTaxonId, Set researcherPositions, Set researcherTypes, Set organUberonIds, Map> ontologyTermInfos ); + List findGenesBySymbol( String symbol, Taxon taxon, Set tier, @Nullable Integer orthologTaxonId, @Nullable Set researcherPositions, @Nullable Set researcherTypes, @Nullable Set organUberonIds, @Nullable Map> ontologyTermInfos ); /** * Retrieve a user from a specific registry. @@ -94,6 +95,7 @@ public interface RemoteResourceService { * * @see ApiController#getUserByAnonymousId(UUID, Locale) */ + @Nullable User getAnonymizedUser( UUID anonymousId, URI remoteHost ) throws RemoteException; /** diff --git a/src/main/java/ubc/pavlab/rdp/services/RemoteResourceServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/RemoteResourceServiceImpl.java index 6ee1f2dc..daf49e53 100644 --- a/src/main/java/ubc/pavlab/rdp/services/RemoteResourceServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/RemoteResourceServiceImpl.java @@ -15,6 +15,7 @@ import org.springframework.context.annotation.Lazy; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.lang.Nullable; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; import org.springframework.util.LinkedMultiValueMap; @@ -248,7 +249,7 @@ public List findUsersByDescription( String descriptionLike, Set findUsersByLikeNameAndDescription( String nameLike, boolean prefix, String descriptionLike, Set researcherPositions, Set researcherCategories, Set organUberonIds, Map> ontologyTermInfos ) { + public List findUsersByLikeNameAndDescription( String nameLike, boolean prefix, String descriptionLike, @Nullable Set researcherPositions, @Nullable Set researcherCategories, @Nullable Set organUberonIds, @Nullable Map> ontologyTermInfos ) { MultiValueMap params = new LinkedMultiValueMap<>(); params.add( "nameLike", nameLike ); params.add( "prefix", String.valueOf( prefix ) ); @@ -268,7 +269,7 @@ public List findUsersByLikeNameAndDescription( String nameLike, boolean pr return null; } if ( VersionUtils.satisfiesVersion( apiVersion, "1.5.0" ) ) { - return chain.filter( apiUri, chain ); + return chain != null ? chain.filter( apiUri, chain ) : null; } else if ( ontologyTermInfos != null ) { // pre-1.5 registry do not support ontology terms return CompletableFuture.completedFuture( ResponseEntity.ok( new User[0] ) ); @@ -311,8 +312,7 @@ public List findUsersByLikeNameAndDescription( String nameLike, boolean pr @Override - public List findGenesBySymbol( String symbol, Taxon taxon, Set tiers, Integer - orthologTaxonId, Set researcherPositions, Set researcherCategories, Set organUberonIds, Map> ontologyTermInfos ) { + public List findGenesBySymbol( String symbol, Taxon taxon, Set tiers, @Nullable Integer orthologTaxonId, @Nullable Set researcherPositions, @Nullable Set researcherCategories, @Nullable Set organUberonIds, @Nullable Map> ontologyTermInfos ) { List intlUsergenes = new LinkedList<>(); for ( TierType tier : restrictTiers( tiers ) ) { MultiValueMap params = new LinkedMultiValueMap<>(); @@ -577,7 +577,8 @@ private interface RequestFilter { * @return the result of the step, or null to abort the chain * @ */ - Future> filter( URI apiUri, RequestFilter next ); + @Nullable + Future> filter( URI apiUri, @Nullable RequestFilter next ); } /** @@ -593,7 +594,7 @@ private RequestFilter satisfiesVersion( String minimumVersion ) { return null; } if ( VersionUtils.satisfiesVersion( apiVersion, minimumVersion ) ) { - return next.filter( apiUri, null ); + return next != null ? next.filter( apiUri, null ) : null; } else { return null; } diff --git a/src/main/java/ubc/pavlab/rdp/services/TaxonService.java b/src/main/java/ubc/pavlab/rdp/services/TaxonService.java index 2cf4e369..647b0452 100644 --- a/src/main/java/ubc/pavlab/rdp/services/TaxonService.java +++ b/src/main/java/ubc/pavlab/rdp/services/TaxonService.java @@ -1,5 +1,6 @@ package ubc.pavlab.rdp.services; +import org.springframework.lang.Nullable; import ubc.pavlab.rdp.model.Taxon; import java.util.Collection; @@ -9,6 +10,7 @@ */ public interface TaxonService { + @Nullable Taxon findById( final Integer id ); Collection findByActiveTrue(); diff --git a/src/main/java/ubc/pavlab/rdp/services/UserGeneService.java b/src/main/java/ubc/pavlab/rdp/services/UserGeneService.java index 4502447a..65fcea46 100644 --- a/src/main/java/ubc/pavlab/rdp/services/UserGeneService.java +++ b/src/main/java/ubc/pavlab/rdp/services/UserGeneService.java @@ -21,6 +21,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.lang.Nullable; import ubc.pavlab.rdp.model.*; import ubc.pavlab.rdp.model.enums.PrivacyLevelType; import ubc.pavlab.rdp.model.enums.ResearcherCategory; @@ -29,7 +30,10 @@ import ubc.pavlab.rdp.model.ontology.Ontology; import ubc.pavlab.rdp.model.ontology.OntologyTermInfo; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * Created by mjacobson on 17/01/18. @@ -70,7 +74,7 @@ public interface UserGeneService { * @param organs only retain results where the corresponding {@link User} tracks any of the given {@link OrganInfo} * @param ontologyTermInfos */ - List handleGeneSearch( Gene gene, Set tiers, Taxon orthologTaxon, Set researcherPositions, Collection researcherTypes, Collection organs, Map> ontologyTermInfos ); + List handleGeneSearch( Gene gene, @Nullable Set tiers, @Nullable Taxon orthologTaxon, @Nullable Set researcherPositions, @Nullable Collection researcherTypes, @Nullable Collection organs, @Nullable Map> ontologyTermInfos ); void updateUserGenes(); } diff --git a/src/main/java/ubc/pavlab/rdp/services/UserPrivacyService.java b/src/main/java/ubc/pavlab/rdp/services/UserPrivacyService.java index 2d09ae68..ee0ff87c 100644 --- a/src/main/java/ubc/pavlab/rdp/services/UserPrivacyService.java +++ b/src/main/java/ubc/pavlab/rdp/services/UserPrivacyService.java @@ -3,6 +3,7 @@ import lombok.extern.apachecommons.CommonsLog; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; +import org.springframework.lang.Nullable; import org.springframework.stereotype.Service; import ubc.pavlab.rdp.model.Profile; import ubc.pavlab.rdp.model.Role; @@ -14,6 +15,8 @@ import java.text.MessageFormat; +import static java.util.Objects.requireNonNull; + @Service @CommonsLog public class UserPrivacyService { @@ -27,11 +30,11 @@ public class UserPrivacyService { @Autowired private ApplicationSettings applicationSettings; - public boolean checkUserCanSee( User user, UserContent content ) { + public boolean checkUserCanSee( @Nullable User user, UserContent content ) { return checkUserCanSeeOtherUserContentWithPrivacyLevel( user, content.getOwner().orElse( null ), content.getEffectivePrivacyLevel() ); } - public boolean checkUserCanSearch( User user, boolean international ) { + public boolean checkUserCanSearch( @Nullable User user, boolean international ) { // international search is not enabled if ( international && !applicationSettings.getIsearch().isEnabled() ) { return false; @@ -46,12 +49,12 @@ public boolean checkCurrentUserCanSearch( boolean international ) { return checkUserCanSearch( userService.findCurrentUser(), international ); } - public boolean checkUserCanUpdate( User user, UserContent userContent ) { + public boolean checkUserCanUpdate( @Nullable User user, UserContent userContent ) { // only admins or rightful owner can update user content return user != null && ( user.getRoles().contains( getAdminRole() ) || userContent.getOwner().filter( user::equals ).isPresent() ); } - private boolean checkUserCanSeeOtherUserContentWithPrivacyLevel( User currentUser, User otherUser, PrivacyLevelType privacyLevel ) { + private boolean checkUserCanSeeOtherUserContentWithPrivacyLevel( @Nullable User currentUser, @Nullable User otherUser, PrivacyLevelType privacyLevel ) { // Never show the remote admin profile (or accidental null users) if ( otherUser == null || ( applicationSettings.getIsearch() != null && isRemoteSearchUser( otherUser ) ) ) { return false; @@ -96,12 +99,12 @@ public boolean checkCurrentUserCanSeeGeneList( User otherUser ) { @Cacheable(value = "ubc.pavlab.rdp.model.Role.byRole", key = "'ROLE_ADMIN'") public Role getAdminRole() { - return roleRepository.findByRole( "ROLE_ADMIN" ); + return requireNonNull( roleRepository.findByRole( "ROLE_ADMIN" ) ); } @Cacheable(value = "ubc.pavlab.rdp.model.Role.byRole", key = "'ROLE_SERVICE_ACCOUNT'") public Role getServiceAccountRole() { - return roleRepository.findByRole( "ROLE_SERVICE_ACCOUNT" ); + return requireNonNull( roleRepository.findByRole( "ROLE_SERVICE_ACCOUNT" ) ); } private boolean isRemoteSearchUser( User user ) { diff --git a/src/main/java/ubc/pavlab/rdp/services/UserService.java b/src/main/java/ubc/pavlab/rdp/services/UserService.java index 6926de53..79eca75d 100644 --- a/src/main/java/ubc/pavlab/rdp/services/UserService.java +++ b/src/main/java/ubc/pavlab/rdp/services/UserService.java @@ -49,18 +49,24 @@ public interface UserService { String getCurrentEmail(); + @Nullable User findCurrentUser(); boolean isCurrentUser( User user ); + @Nullable User findUserById( int id ); + @Nullable User findUserByAnonymousIdNoAuth( UUID anonymousId ); + @Nullable UserGene findUserGeneByAnonymousIdNoAuth( UUID anonymousId ); + @Nullable User findUserByIdNoAuth( int id ); + @Nullable User findUserByEmailNoAuth( String email ); User findUserByAccessTokenNoAuth( String accessToken ) throws TokenException; @@ -130,23 +136,23 @@ public interface UserService { *

* Note: results are sorted according to {@link User#getComparator()}. */ - List findByLikeName( String nameLike, Set researcherPositions, Set researcherTypes, Collection userOrgans, Map> ontologyTermInfos ); + List findByLikeName( String nameLike, @Nullable Set researcherPositions, @Nullable Set researcherTypes, @Nullable Collection userOrgans, @Nullable Map> ontologyTermInfos ); /** * Find users by their name using a prefix match. *

* Note: results are sorted according to {@link User#getComparator()}. */ - List findByStartsName( String startsName, Set researcherPositions, Set researcherTypes, Collection userOrgans, Map> ontologyTermInfos ); + List findByStartsName( String startsName, @Nullable Set researcherPositions, @Nullable Set researcherTypes, @Nullable Collection userOrgans, @Nullable Map> ontologyTermInfos ); /** * Find users by their description and sorted according to {@link User#getComparator()}. *

* Note: results are sorted according to {@link User#getComparator()}. */ - List findByDescription( String descriptionLike, Set researcherPositions, Collection researcherTypes, Collection userOrgans, Map> ontologyTermInfos ); + List findByDescription( String descriptionLike, @Nullable Set researcherPositions, @Nullable Collection researcherTypes, @Nullable Collection userOrgans, @Nullable Map> ontologyTermInfos ); - List findByNameAndDescription( String nameLike, boolean prefix, String descriptionLike, Set researcherPositions, Set researcherCategories, Collection userOrgans, Map> ontologyTermInfos ); + List findByNameAndDescription( String nameLike, boolean prefix, String descriptionLike, @Nullable Set researcherPositions, @Nullable Set researcherCategories, @Nullable Collection userOrgans, @Nullable Map> ontologyTermInfos ); Set getUserTermInfoIds( User user ); @@ -179,8 +185,8 @@ User updateTermsAndGenesInTaxon( User user, User updateUserProfileAndPublicationsAndOrgansAndOntologyTerms( User user, Profile profile, Set publications, - Set organUberonIds, - Set ontologyTermIds, + @Nullable Set organUberonIds, + @Nullable Set ontologyTermIds, Locale locale ); PasswordResetToken createPasswordResetTokenForUser( User user, Locale locale ); diff --git a/src/main/java/ubc/pavlab/rdp/services/UserServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/UserServiceImpl.java index fd93dbda..dd6ece3e 100644 --- a/src/main/java/ubc/pavlab/rdp/services/UserServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/UserServiceImpl.java @@ -1,6 +1,5 @@ package ubc.pavlab.rdp.services; -import lombok.NonNull; import lombok.extern.apachecommons.CommonsLog; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.InitializingBean; @@ -57,6 +56,7 @@ import java.util.function.Predicate; import java.util.stream.Collectors; +import static java.util.Objects.requireNonNull; import static java.util.function.Function.identity; import static ubc.pavlab.rdp.util.CollectionUtils.containsAtLeastOne; import static ubc.pavlab.rdp.util.CollectionUtils.nullOrContainsAtLeastOne; @@ -222,7 +222,7 @@ public void delete( User user ) { @Override public User changePassword( String oldPassword, String newPassword ) throws BadCredentialsException, ValidationException { - User user = findCurrentUser(); + User user = requireNonNull( findCurrentUser() ); if ( bCryptPasswordEncoder.matches( oldPassword, user.getPassword() ) ) { if ( newPassword.length() >= 6 ) { //TODO: Tie in with hibernate constraint on User or not necessary? @@ -287,7 +287,6 @@ public User findUserById( int id ) { * There is no authorization check performed, so make sure that you reuse anonymizeUser before presenting the data * in the view. * - * @param anonymousId * @return the user if found, otherwise null */ @Override @@ -303,7 +302,6 @@ public User findUserByAnonymousIdNoAuth( UUID anonymousId ) { * There is no authorization check performed, so make sure that you reuse anonymizeUserGene before presenting the * data in the view. * - * @param anonymousId * @return the user's gene if found, otherwise null */ @Override @@ -405,12 +403,6 @@ public Optional getRemoteSearchUser() { .flatMap( userRepository::findOneWithRoles ); } - /** - * Results are ored - * - * @param pageable - * @return - */ @Override public Page findAllNoAuth( Pageable pageable ) { return userRepository.findAll( pageable ); @@ -559,13 +551,13 @@ public Collection convertTerms( User user, Taxon taxon, Collection recommendTerms( @NonNull User user, Taxon taxon, List feedback ) { + public Collection recommendTerms( User user, Taxon taxon, @Nullable List feedback ) { return recommendTerms( user, user.getGenesByTaxonAndTier( taxon, getManualTiers() ), taxon, applicationSettings.getGoTermSizeLimit(), applicationSettings.getGoTermMinOverlap(), feedback ); } @Override @PostFilter("hasPermission(filterObject, 'read')") - public Collection recommendTerms( User user, Set genes, Taxon taxon, List feedback ) { + public Collection recommendTerms( User user, Set genes, Taxon taxon, @Nullable List feedback ) { return recommendTerms( user, genes, taxon, applicationSettings.getGoTermSizeLimit(), applicationSettings.getGoTermMinOverlap(), feedback ); } @@ -573,7 +565,7 @@ public Collection recommendTerms( User user, Set genes * This is only meant for testing purposes; refrain from using in actual code. */ @PostFilter("hasPermission(filterObject, 'read')") - Collection recommendTerms( @NonNull User user, @NonNull Taxon taxon, long maxSize, long minFrequency ) { + Collection recommendTerms( User user, Taxon taxon, long maxSize, long minFrequency ) { return recommendTerms( user, user.getGenesByTaxonAndTier( taxon, getManualTiers() ), taxon, maxSize, minFrequency, null ); } @@ -588,7 +580,7 @@ Collection recommendTerms( @NonNull User user, @NonNull Taxon taxon, l * @param feedback feedback is appended in the form of {@link MessageSourceResolvable} if non-null * @return the recommended terms for the given parameters */ - private Collection recommendTerms( @NonNull User user, Set genes, Taxon taxon, long maxSize, long minFrequency, @Nullable List feedback ) { + private Collection recommendTerms( User user, Set genes, Taxon taxon, long maxSize, long minFrequency, @Nullable List feedback ) { // terms already associated to user within the taxon Set userTermGoIds = user.getUserTerms().stream() .filter( ut -> ut.getTaxon().equals( taxon ) ) @@ -715,9 +707,13 @@ public User updateTermsAndGenesInTaxon( User user, // update frequency and size as those have likely changed with new genes for ( UserTerm userTerm : user.getUserTerms() ) { - GeneOntologyTermInfo cachedTerm = goService.getTerm( userTerm.getGoId() ); userTerm.setFrequency( computeTermFrequencyInTaxon( user, userTerm, taxon ) ); - userTerm.setSize( goService.getSizeInTaxon( cachedTerm, taxon ) ); + GeneOntologyTermInfo cachedTerm = goService.getTerm( userTerm.getGoId() ); + if ( cachedTerm != null ) { + userTerm.setSize( goService.getSizeInTaxon( cachedTerm, taxon ) ); + } else { + log.warn( String.format( "Could not find GO term %s to update user term.", userTerm.getGoId() ) ); + } } return update( user ); @@ -733,11 +729,6 @@ public long computeTermOverlaps( UserTerm userTerm, Collection genes ) /** * Compute the number of TIER1/TIER2 user genes that are associated to a given ontology term. - * - * @param user - * @param term - * @param taxon - * @return */ @Override public long computeTermFrequencyInTaxon( User user, GeneOntologyTerm term, Taxon taxon ) { @@ -762,7 +753,7 @@ public void sendGeneAccessRequest( User requestingUser, UserGene userGene, Strin @Transactional @Override @PreAuthorize("hasPermission(#user, 'update')") - public User updateUserProfileAndPublicationsAndOrgansAndOntologyTerms( User user, Profile profile, Set publications, Set organUberonIds, Set termIdsByOntologyId, Locale locale ) { + public User updateUserProfileAndPublicationsAndOrgansAndOntologyTerms( User user, Profile profile, @Nullable Set publications, @Nullable Set organUberonIds, @Nullable Set termIdsByOntologyId, Locale locale ) { user.getProfile().setDepartment( profile.getDepartment() ); user.getProfile().setDescription( profile.getDescription() ); user.getProfile().setLastName( profile.getLastName() ); @@ -836,7 +827,7 @@ public User updateUserProfileAndPublicationsAndOrgansAndOntologyTerms( User user user.getProfile().getPublications().addAll( publications ); } - if ( applicationSettings.getOrgans().isEnabled() ) { + if ( applicationSettings.getOrgans().isEnabled() && organUberonIds != null ) { Map userOrgans = organInfoService.findByUberonIdIn( organUberonIds ).stream() .map( organInfo -> user.getUserOrgans().getOrDefault( organInfo.getUberonId(), UserOrgan.createFromOrganInfo( user, organInfo ) ) ) .collect( Collectors.toMap( Organ::getUberonId, identity() ) ); @@ -899,7 +890,7 @@ public User changePasswordByResetToken( int userId, String token, PasswordReset PasswordResetToken passToken = verifyPasswordResetToken( userId, token, request ); // Preauthorize might cause trouble here if implemented, fix by setting manual authentication - User user = findUserByIdNoAuth( userId ); + User user = requireNonNull( findUserByIdNoAuth( userId ) ); user.setPassword( bCryptPasswordEncoder.encode( passwordReset.getNewPassword() ) ); diff --git a/src/main/java/ubc/pavlab/rdp/services/package-info.java b/src/main/java/ubc/pavlab/rdp/services/package-info.java new file mode 100644 index 00000000..ddaeedbe --- /dev/null +++ b/src/main/java/ubc/pavlab/rdp/services/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +@NonNullApi +package ubc.pavlab.rdp.services; + +import org.springframework.lang.NonNullApi; \ No newline at end of file diff --git a/src/main/java/ubc/pavlab/rdp/util/CollectionUtils.java b/src/main/java/ubc/pavlab/rdp/util/CollectionUtils.java index 219afc54..405367cb 100644 --- a/src/main/java/ubc/pavlab/rdp/util/CollectionUtils.java +++ b/src/main/java/ubc/pavlab/rdp/util/CollectionUtils.java @@ -1,6 +1,6 @@ package ubc.pavlab.rdp.util; -import lombok.NonNull; +import org.springframework.lang.NonNull; import java.util.Collection; import java.util.HashMap; diff --git a/src/main/java/ubc/pavlab/rdp/util/Gene2GoParser.java b/src/main/java/ubc/pavlab/rdp/util/Gene2GoParser.java index afc24da7..c127cc23 100644 --- a/src/main/java/ubc/pavlab/rdp/util/Gene2GoParser.java +++ b/src/main/java/ubc/pavlab/rdp/util/Gene2GoParser.java @@ -6,6 +6,7 @@ import lombok.extern.apachecommons.CommonsLog; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.time.StopWatch; +import org.springframework.lang.Nullable; import java.io.IOException; import java.io.InputStream; @@ -28,12 +29,13 @@ public class Gene2GoParser { GENE_ID_INDEX = ArrayUtils.indexOf( EXPECTED_FIELDS, GENE_ID_FIELD ), GO_ID_INDEX = ArrayUtils.indexOf( EXPECTED_FIELDS, GO_ID_FIELD ); + @Nullable private final Set retainedTaxa; /** * @param retainedTaxa a set of taxa to retain from the gene2go input, or null to ignore */ - public Gene2GoParser( Set retainedTaxa ) { + public Gene2GoParser( @Nullable Set retainedTaxa ) { this.retainedTaxa = retainedTaxa; } diff --git a/src/main/java/ubc/pavlab/rdp/util/ProgressUtils.java b/src/main/java/ubc/pavlab/rdp/util/ProgressUtils.java index b9e9f473..afbc8a6f 100644 --- a/src/main/java/ubc/pavlab/rdp/util/ProgressUtils.java +++ b/src/main/java/ubc/pavlab/rdp/util/ProgressUtils.java @@ -2,6 +2,7 @@ import lombok.extern.apachecommons.CommonsLog; import org.apache.commons.lang3.time.StopWatch; +import org.springframework.lang.Nullable; import java.time.Duration; import java.util.concurrent.TimeUnit; @@ -19,7 +20,7 @@ public class ProgressUtils { * @param totalElements total number of elements to be processed, which must be greater than one * @param elapsedTime elapsed time since the processing started */ - public static void emitProgress( ProgressCallback progressCallback, long processedElements, long totalElements, Duration elapsedTime ) { + public static void emitProgress( @Nullable ProgressCallback progressCallback, long processedElements, long totalElements, Duration elapsedTime ) { if ( processedElements < 0 ) { throw new IllegalArgumentException( "The processedElements parameter must be positive." ); } @@ -44,7 +45,7 @@ public static void emitProgress( ProgressCallback progressCallback, long process } } - public static void emitProgress( ProgressCallback progressCallback, long processedElements, long totalElements, long elapsedTimeMillis ) { + public static void emitProgress( @Nullable ProgressCallback progressCallback, long processedElements, long totalElements, long elapsedTimeMillis ) { emitProgress( progressCallback, processedElements, totalElements, Duration.ofMillis( elapsedTimeMillis ) ); } } diff --git a/src/main/java/ubc/pavlab/rdp/util/SearchResult.java b/src/main/java/ubc/pavlab/rdp/util/SearchResult.java index 3b39a649..aa84e14e 100644 --- a/src/main/java/ubc/pavlab/rdp/util/SearchResult.java +++ b/src/main/java/ubc/pavlab/rdp/util/SearchResult.java @@ -2,6 +2,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; +import org.springframework.lang.Nullable; import java.util.Comparator; @@ -39,6 +40,7 @@ public class SearchResult> implements Comparable { @@ -25,7 +27,7 @@ public static Version parseVersion( String version ) throws VersionException { * @param preRelease * @throws VersionException if the components contains an invalid number */ - public Version( String[] components, String preRelease ) throws VersionException { + public Version( String[] components, @Nullable String preRelease ) throws VersionException { if ( components.length > FACTORS.length ) { throw new VersionException( "Version must have at most " + FACTORS.length + " components." ); } diff --git a/src/main/java/ubc/pavlab/rdp/util/package-info.java b/src/main/java/ubc/pavlab/rdp/util/package-info.java new file mode 100644 index 00000000..4569f0c5 --- /dev/null +++ b/src/main/java/ubc/pavlab/rdp/util/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +@NonNullApi +package ubc.pavlab.rdp.util; + +import org.springframework.lang.NonNullApi; \ No newline at end of file diff --git a/src/main/java/ubc/pavlab/rdp/validation/EmailValidator.java b/src/main/java/ubc/pavlab/rdp/validation/EmailValidator.java index da5db924..e559a027 100644 --- a/src/main/java/ubc/pavlab/rdp/validation/EmailValidator.java +++ b/src/main/java/ubc/pavlab/rdp/validation/EmailValidator.java @@ -1,6 +1,7 @@ package ubc.pavlab.rdp.validation; import org.apache.commons.lang3.StringUtils; +import org.springframework.lang.Nullable; import org.springframework.validation.Errors; import org.springframework.validation.Validator; @@ -34,7 +35,7 @@ public EmailValidator() { this.allowIdn = false; } - public EmailValidator( AllowedDomainStrategy allowedDomainStrategy, boolean allowIdn ) { + public EmailValidator( @Nullable AllowedDomainStrategy allowedDomainStrategy, boolean allowIdn ) { this.allowedDomainStrategy = allowedDomainStrategy; this.allowIdn = allowIdn; } diff --git a/src/main/java/ubc/pavlab/rdp/validation/ResourceBasedAllowedDomainStrategy.java b/src/main/java/ubc/pavlab/rdp/validation/ResourceBasedAllowedDomainStrategy.java index 2d8eac86..d3f732f5 100644 --- a/src/main/java/ubc/pavlab/rdp/validation/ResourceBasedAllowedDomainStrategy.java +++ b/src/main/java/ubc/pavlab/rdp/validation/ResourceBasedAllowedDomainStrategy.java @@ -5,6 +5,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.StopWatch; import org.springframework.core.io.Resource; +import org.springframework.lang.Nullable; import java.io.BufferedReader; import java.io.FileNotFoundException; @@ -55,7 +56,7 @@ public class ResourceBasedAllowedDomainStrategy implements AllowedDomainStrategy private volatile SetBasedAllowedDomainStrategy strategy; private long lastRefresh; - public ResourceBasedAllowedDomainStrategy( Resource allowedEmailDomainsFile, Duration refreshDelay ) { + public ResourceBasedAllowedDomainStrategy( Resource allowedEmailDomainsFile, @Nullable Duration refreshDelay ) { this.allowedEmailDomainsFile = allowedEmailDomainsFile; this.refreshDelay = refreshDelay; } diff --git a/src/main/java/ubc/pavlab/rdp/validation/package-info.java b/src/main/java/ubc/pavlab/rdp/validation/package-info.java new file mode 100644 index 00000000..98f9cd6c --- /dev/null +++ b/src/main/java/ubc/pavlab/rdp/validation/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +@NonNullApi +package ubc.pavlab.rdp.validation; + +import org.springframework.lang.NonNullApi; \ No newline at end of file diff --git a/src/test/java/ubc/pavlab/rdp/services/GOServiceImplTest.java b/src/test/java/ubc/pavlab/rdp/services/GOServiceImplTest.java index 833d9969..bc869c98 100644 --- a/src/test/java/ubc/pavlab/rdp/services/GOServiceImplTest.java +++ b/src/test/java/ubc/pavlab/rdp/services/GOServiceImplTest.java @@ -154,14 +154,9 @@ private GeneOntologyTermInfo initializeTerm( GeneOntologyTermInfo term ) { return term; } - @Test(expected = NullPointerException.class) - public void termFrequencyMap_whenGenesNull_thenThroNullPointerException() { - Map fmap = goService.termFrequencyMap( null ); - } - @Test public void termFrequencyMap_whenGenesEmpty_thenReturnEmpty() { - Map fmap = goService.termFrequencyMap( Collections.EMPTY_SET ); + Map fmap = goService.termFrequencyMap( Collections.emptySet() ); assertThat( fmap ).isEmpty(); } @@ -285,11 +280,6 @@ public void search_whenMultipleMatchesAndResultsUnlimited_thenReturnAll() { assertThat( matches ).hasSize( 90 ); } - @Test(expected = NullPointerException.class) - public void getChildren_whenNull_thenReturnNull() { - Collection found = goService.getChildren( null ); - } - @Test public void getChildren_whenDefault_thenReturnAllChildren() { Collection found = goService.getChildren( terms.get( 1 ) ); @@ -302,11 +292,6 @@ public void getChildren_whenIncludePartOf_thenReturnAllChildren() { assertThat( found ).containsExactlyInAnyOrder( terms.get( 2 ), terms.get( 3 ) ); } - @Test(expected = NullPointerException.class) - public void getDescendants_whenNull_thenReturnNull() { - Collection found = goService.getDescendants( null ); - } - @Test public void getDescendants_whenTermIsRoot_thenReturnAllChildren() { Collection found = goService.getDescendants( terms.get( 0 ) ); @@ -343,18 +328,6 @@ public void getGenes_whenValidStringAndInvalidTaxon_thenReturnEmpty() { assertThat( found ).isEmpty(); } - @Test - public void getGenes_whenNullString_thenReturnNull() { - String goId = null; - Collection found = goService.getGenesInTaxon( goId, taxon ); - assertThat( found ).isEmpty(); - } - - @Test(expected = NullPointerException.class) - public void getGenes_whenValidStringAndNullTaxon_thenReturnNull() { - Collection found = goService.getGenesInTaxon( terms.get( 0 ).getGoId(), null ); - } - @Test public void getGenes_whenValidTerm_thenReturnGenes() { Collection found = goService.getGenes( terms.get( 0 ) ); @@ -373,12 +346,6 @@ public void getGenes_whenInvalidTerm_thenReturnEmpty() { assertThat( found ).isEmpty(); } - @Test(expected = NullPointerException.class) - public void getGenes_whenNullTerm_thenReturnNull() { - GeneOntologyTermInfo term = null; - Collection found = goService.getGenes( term ); - } - @Test public void getGenes_whenValidTermAndTaxon_thenReturnGenes() { Collection found = goService.getGenesInTaxon( terms.get( 0 ), taxon ); @@ -397,17 +364,6 @@ public void getGenes_whenInvalidTaxon_thenReturnEmpty() { assertThat( found ).isEmpty(); } - @Test(expected = NullPointerException.class) - public void getGenes_whenNullTermAndTaxon_thenReturnNull() { - GeneOntologyTermInfo term = null; - Collection found = goService.getGenesInTaxon( term, taxon ); - } - - @Test(expected = NullPointerException.class) - public void getGenes_whenNullTaxon_thenReturnNull() { - Collection found = goService.getGenesInTaxon( terms.get( 0 ), null ); - } - // @Test @@ -431,17 +387,6 @@ public void getGenes_whenMultipleTermsAndInvalidTaxon_thenReturnEmpty() { assertThat( found ).isEmpty(); } - @Test(expected = NullPointerException.class) - public void getGenes_whenNullTermsAndTaxon_thenReturnNull() { - Collection terms = null; - Collection found = goService.getGenesInTaxon( terms, taxon ); - } - - @Test(expected = NullPointerException.class) - public void getGenes_whenMultipleTermsAndNullTaxon_thenReturnNull() { - Collection found = goService.getGenesInTaxon( Sets.newSet( terms.get( 1 ), terms.get( 4 ) ), null ); - } - @Test public void getTerm_whenValidId_thenReturnTerm() { GeneOntologyTerm found = goService.getTerm( terms.get( 1 ).getGoId() ); @@ -454,12 +399,6 @@ public void getTerm_whenInvalidId_thenReturnNull() { assertThat( found ).isNull(); } - @Test - public void getTerm_whenNullId_thenReturnNull() { - GeneOntologyTerm found = goService.getTerm( null ); - assertThat( found ).isNull(); - } - @Test public void updateGoTerms() { goService.updateGoTerms(); diff --git a/src/test/java/ubc/pavlab/rdp/services/OntologyServiceTest.java b/src/test/java/ubc/pavlab/rdp/services/OntologyServiceTest.java index af1b29fb..789ffeac 100644 --- a/src/test/java/ubc/pavlab/rdp/services/OntologyServiceTest.java +++ b/src/test/java/ubc/pavlab/rdp/services/OntologyServiceTest.java @@ -382,7 +382,7 @@ public void move() { .containsExactly( "ont0", "ont1", "ont2", "ont3", "ont4" ); Ontology ontology = ontologyService.findByName( "ont" + 3 ); - assertThat( ontology ).hasFieldOrPropertyWithValue( "ordering", 4 ); + assertThat( ontology ).isNotNull().hasFieldOrPropertyWithValue( "ordering", 4 ); ontologyService.move( ontology, OntologyService.Direction.UP ); @@ -404,7 +404,7 @@ public void move_whenOntologiesDontHaveSpecifiedOrder() { .containsExactly( "ont0", "ont1", "ont2", "ont3", "ont4" ); Ontology ontology = ontologyService.findByName( "ont" + 3 ); - assertThat( ontology ).hasFieldOrPropertyWithValue( "ordering", null ); + assertThat( ontology ).isNotNull().hasFieldOrPropertyWithValue( "ordering", null ); ontologyService.move( ontology, OntologyService.Direction.UP ); diff --git a/src/test/java/ubc/pavlab/rdp/services/UserServiceImplTest.java b/src/test/java/ubc/pavlab/rdp/services/UserServiceImplTest.java index 2cc4717e..3c2c5799 100644 --- a/src/test/java/ubc/pavlab/rdp/services/UserServiceImplTest.java +++ b/src/test/java/ubc/pavlab/rdp/services/UserServiceImplTest.java @@ -411,6 +411,7 @@ public void findUserByEmail_whenValidEmail_thenUserShouldBeFound() { when( userRepository.findByEmailIgnoreCase( user.getEmail() ) ).thenReturn( user ); User found = userService.findUserByEmailNoAuth( user.getEmail() ); + assertThat( found ).isNotNull(); assertThat( found.getEmail() ) .isEqualTo( user.getEmail() ); } @@ -1300,24 +1301,6 @@ public void recommendTerms_whenUserHasNoGenes_thenReturnEmpty() { assertThat( found ).isEmpty(); } - @Test(expected = NullPointerException.class) - public void recommendTerms_whenUserNull_thenThrowNullPointerException() { - setUpRecommendTermsMocks(); - - Taxon taxon = createTaxon( 1 ); - Collection found = userService.recommendTerms( null, taxon, -1, -1 ); - assertThat( found ).isNull(); - } - - @Test(expected = NullPointerException.class) - public void recommendTerms_whenTaxonNull_thenThrowNullPointerException() { - setUpRecommendTermsMocks(); - - User user = createUser( 1 ); - userService.recommendTerms( user, null, -1, -1 ); - } - - @Test public void updateUserTerms_thenSucceed() { userService.updateUserTerms(); diff --git a/src/test/java/ubc/pavlab/rdp/util/TestUtils.java b/src/test/java/ubc/pavlab/rdp/util/TestUtils.java index b827b552..f2dfe397 100644 --- a/src/test/java/ubc/pavlab/rdp/util/TestUtils.java +++ b/src/test/java/ubc/pavlab/rdp/util/TestUtils.java @@ -1,6 +1,7 @@ package ubc.pavlab.rdp.util; import lombok.SneakyThrows; +import org.springframework.lang.Nullable; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; @@ -176,13 +177,13 @@ public static UserTerm createUserTerm( int id, User user, GeneOntologyTerm term, return ut; } - public static UserGene createUserGene( int id, Gene gene, User user, TierType tier, PrivacyLevelType privacyLevelType ) { + public static UserGene createUserGene( int id, Gene gene, User user, TierType tier, @Nullable PrivacyLevelType privacyLevelType ) { UserGene ug = createUnpersistedUserGene( gene, user, tier, privacyLevelType ); ug.setId( id ); return ug; } - public static UserGene createUnpersistedUserGene( Gene gene, User user, TierType tier, PrivacyLevelType privacyLevelType ) { + public static UserGene createUnpersistedUserGene( Gene gene, User user, TierType tier, @Nullable PrivacyLevelType privacyLevelType ) { UserGene ug = new UserGene(); ug.setUser( user ); ug.setTier( tier ); @@ -195,7 +196,7 @@ public static String toGOId( int id ) { return String.format( "GO:%07d", id ); } - public static OrganInfo createOrgan( String uberonId, String name, String description ) { + public static OrganInfo createOrgan( String uberonId, @Nullable String name, @Nullable String description ) { OrganInfo oi = new OrganInfo(); oi.setUberonId( uberonId ); oi.setName( name );