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

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
DATAREST-78. Remove leading slash in @query path.
  • Loading branch information
fbiville authored and Florent Biville committed Jun 12, 2013
commit 42efbe7357a574d8fb461ce5bf803dff5bf9400b
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package org.springframework.data.rest.repository.support;

import static org.springframework.core.annotation.AnnotationUtils.*;
import static org.springframework.util.StringUtils.*;

import java.lang.reflect.Method;

import org.springframework.data.mapping.PersistentEntity;
Expand All @@ -12,6 +9,11 @@
import org.springframework.data.rest.config.ResourceMapping;
import org.springframework.data.rest.repository.annotation.RestResource;

import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
import static org.springframework.data.rest.repository.support.ResourceStringUtils.hasText;
import static org.springframework.data.rest.repository.support.ResourceStringUtils.removeLeadingSlash;
import static org.springframework.util.StringUtils.uncapitalize;

/**
* Helper methods to get the default rel and path values or to use values supplied by annotations.
*
Expand Down Expand Up @@ -56,16 +58,16 @@ public static String formatRel(RepositoryRestConfiguration config,
ResourceMapping propertyMapping = entityMapping.getResourceMappingFor(persistentProperty.getName());

return String.format("%s.%s.%s",
repoMapping.getRel(),
entityMapping.getRel(),
(null != propertyMapping ? propertyMapping.getRel() : persistentProperty.getName()));
repoMapping.getRel(),
entityMapping.getRel(),
(null != propertyMapping ? propertyMapping.getRel() : persistentProperty.getName()));
}

public static String findPath(Class<?> type) {
RestResource anno;
if(null != (anno = findAnnotation(type, RestResource.class))) {
if(hasText(anno.path())) {
return anno.path();
return removeLeadingSlash(anno.path());
}
}

Expand All @@ -76,7 +78,7 @@ public static String findPath(Method method) {
RestResource anno;
if(null != (anno = findAnnotation(method, RestResource.class))) {
if(hasText(anno.path())) {
return anno.path();
return removeLeadingSlash(anno.path());
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.springframework.data.rest.repository.support;

/**
* Helper methods aiming at handling String representations of resources.
*
* @author Florent Biville
*/
public class ResourceStringUtils {
/**
* Checks whether the given input contains actual text (slash excluded).
* This is a specializing variant of {@link org.springframework.util.StringUtils )}#hasText.
*/
public static boolean hasText(CharSequence input) {
int strLen = input.length();
for (int i = 0; i < strLen; i++) {
if (!Character.isWhitespace(input.charAt(i)) && !startsWithSlash(input.charAt(i))) {
return true;
}
}
return false;
}

/**
* Returns a string without the leading slash, if any.
*/
public static String removeLeadingSlash(String path) {
if (path.length() == 0) {
return path;
}

boolean hasLeadingSlash = startsWithSlash(path);
if (path.length() == 1) {
return hasLeadingSlash ? "" : path;
}
return hasLeadingSlash ? path.substring(1) : path;
}

private static boolean startsWithSlash(String path) {
return path.charAt(0) == '/';
}

private static boolean startsWithSlash(char c) {
return c == '/';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.junit.Test;
import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.repository.domain.jpa.AnnotatedPersonRepository;
import org.springframework.data.rest.repository.domain.jpa.AnnotatedWithLeadingSlashPersonRepository;
import org.springframework.data.rest.repository.domain.jpa.PersonRepository;
import org.springframework.data.rest.repository.domain.jpa.PlainPersonRepository;

Expand Down Expand Up @@ -60,4 +61,52 @@ public void shouldDetectAnnotatedRelAndPathOnMethod() throws Exception {
assertThat(mapping.isExported(), is(true));
}

@Test
public void shouldDetectPathAndRemoveLeadingSlashIfAny() {
ResourceMapping mapping = new ResourceMapping(
findRel(AnnotatedWithLeadingSlashPersonRepository.class),
findPath(AnnotatedWithLeadingSlashPersonRepository.class),
findExported(AnnotatedWithLeadingSlashPersonRepository.class)
);

// The rel attribute defaults to class name
assertThat(mapping.getRel(), is("annotatedWithLeadingSlashPerson"));
assertThat(mapping.getPath(), is("people"));
// The exported defaults to true
assertThat(mapping.isExported(), is(true));
}

@Test
public void shouldDetectPathAndRemoveLeadingSlashIfAnyOnMethod() throws Exception {
Method method = AnnotatedWithLeadingSlashPersonRepository.class.getMethod("findByFirstName", String.class, Pageable.class);
ResourceMapping mapping = new ResourceMapping(
findRel(method),
findPath(method),
findExported(method)
);

// The rel attribute defaults to class name
assertThat(mapping.getRel(), is("findByFirstName"));
assertThat(mapping.getPath(), is("firstname"));
// The exported defaults to true
assertThat(mapping.isExported(), is(true));
}

@Test
public void shouldReturnDefaultIfPathContainsOnlySlashTextOnMethod() throws Exception {
Method method = AnnotatedWithLeadingSlashPersonRepository.class.getMethod("findByLastName", String.class, Pageable.class);
ResourceMapping mapping = new ResourceMapping(
findRel(method),
findPath(method),
findExported(method)
);

// The rel defaults to method name
assertThat(mapping.getRel(), is("findByLastName"));
// The path contains only a leading slash therefore defaults to method name
assertThat(mapping.getPath(), is("findByLastName"));
// The exported defaults to true
assertThat(mapping.isExported(), is(true));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.springframework.data.rest.repository.domain.jpa;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.repository.annotation.RestResource;

/**
* A repository to manage {@link org.springframework.data.rest.repository.domain.jpa.Person}s.
*
* @author Florent Biville
*/
@RestResource(path = "/people")
public interface AnnotatedWithLeadingSlashPersonRepository {

@RestResource(path = "/firstname")
public Page<Person> findByFirstName(@Param("firstName") String firstName, Pageable pageable);

@RestResource(path = " / ")
public Page<Person> findByLastName(@Param("lastName") String firstName, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.springframework.data.rest.repository.support;


import java.util.Arrays;
import java.util.Collection;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.runners.Parameterized.Parameters;

/**
* Ensures proper detection and removal of leading slash in strings.
*
* @author Florent Biville
*/
@RunWith(Parameterized.class)
public class ResourceStringUtilsTest {

private String actual;
private String expected;
private boolean hasText;

public ResourceStringUtilsTest(String testDescription,
String actual,
String expected,
boolean hasText) {
this.actual = actual;
this.expected = expected;
this.hasText = hasText;
}

@Parameters(name = "{0}")
public static Collection<?> parameters() {
return Arrays.asList(new Object[][] {
{"empty string has no text and should remain empty", "", "", false},
{"blank string has no text and should remain as is", " ", " ", false},
{"string made of only a leading slash has no text and should be returned empty", "/", "", false},
{"blank string with only slashes has no text and should be returned as is", " / ", " / ", false},
{"normal string has text and should be returned as such", "hello", "hello", true},
{"normal string with leading slash has text and should be returned without leading slash", "/hello", "hello", true},
});
}

@Test
public void shouldDetectTextPresence() {
assertThat(ResourceStringUtils.hasText(actual), is(hasText));
}

@Test
public void shouldRemoveLeadingSlashIfAny() {
assertThat(ResourceStringUtils.removeLeadingSlash(actual), is(expected));
}
}