/** * Copyright (C) 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ninja.params; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Inject; import com.google.inject.multibindings.Multibinder; import ninja.Context; import ninja.Result; import ninja.RoutingException; import ninja.i18n.Lang; import ninja.i18n.LangImpl; import ninja.session.FlashScope; import ninja.session.Session; import ninja.utils.NinjaMode; import ninja.utils.NinjaProperties; import ninja.utils.NinjaPropertiesImpl; import ninja.validation.*; import org.joda.time.LocalDateTime; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.slf4j.LoggerFactory; import javax.validation.constraints.Max; import javax.validation.constraints.Min; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Method; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.Optional; import ninja.exceptions.BadRequestException; import ninja.utils.NinjaConstant; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; import org.hamcrest.Matchers; import static org.junit.Assert.*; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; import org.mockito.Captor; import org.mockito.Mockito; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** * ControllerMethodInvokerTest. */ @RunWith(MockitoJUnitRunner.class) public class ControllerMethodInvokerWithDeprecatedValidationTest { @Mock private MockController mockController; @Mock private Context context; @Mock private Session session; @Mock private FlashScope flash; private NinjaProperties ninjaProperties; private Lang lang; private Validation validation; @Before public void setUp() throws Exception { this.ninjaProperties = Mockito.spy(new NinjaPropertiesImpl(NinjaMode.test)); this.lang = new LangImpl(this.ninjaProperties); this.validation = new ValidationImpl(); when(this.context.getSession()).thenReturn(this.session); when(this.context.getFlashScope()).thenReturn(this.flash); when(this.context.getValidation()).thenReturn(this.validation); } @Test public void noParameterMethodShouldBeInvoked() throws Exception { create("noParameter").invoke(mockController, context); verify(mockController).noParameter(); } @Test public void contextShouldBePassed() throws Exception { create("context").invoke(mockController, context); verify(mockController).context(context); } @Test public void sessionShouldBePassed() throws Exception { create("session").invoke(mockController, context); verify(mockController).session(session); } @Test public void flashArgumentShouldBePassed() throws Exception { create("flash").invoke(mockController, context); verify(mockController).flash(flash); } @Test public void paramAnnotatedArgumentShouldBePassed() throws Exception { when(context.getParameter("param1")).thenReturn("value"); create("param").invoke(mockController, context); verify(mockController).param("value"); } @Test public void pathParamAnnotatedArgumentShouldBePassed() throws Exception { when(context.getPathParameter("param1")).thenReturn("value"); create("pathParam").invoke(mockController, context); verify(mockController).pathParam("value"); } @Test public void sessionParamAnnotatedArgumentShouldBePassed() throws Exception { when(session.get("param1")).thenReturn("value"); create("sessionParam").invoke(mockController, context); verify(mockController).sessionParam("value"); } @Test public void attributeAnnotatedArgumentShouldBePassed() throws Exception { Dep dep = new Dep("dep"); when(context.getAttribute("param1", Dep.class)).thenReturn(dep); create("attribute").invoke(mockController, context); verify(mockController).attribute(dep); } @Test public void headerAnnotatedArgumentShouldBePassed() throws Exception { when(context.getHeader("param1")).thenReturn("value"); create("header").invoke(mockController, context); verify(mockController).header("value"); } @Test public void headerAnnotatedArgumentShouldHandleNull() throws Exception { when(context.getHeader("param1")).thenReturn(null); create("header").invoke(mockController, context); verify(mockController).header(null); } @Test public void headersAnnotatedArgumentShouldReturnNull() throws Exception { when(context.getHeaders("param1")).thenReturn(new ArrayList<String>()); create("headers").invoke(mockController, context); verify(mockController).headers(null); } @Test public void headersAnnotatedArgumentShouldBePassed() throws Exception { when(context.getHeaders("param1")).thenReturn(Arrays.asList("a", "b", "c")); create("headers").invoke(mockController, context); verify(mockController).headers(new String[]{"a", "b", "c"}); } @Test public void headersAnnotatedArgumentShouldHandleNull() throws Exception { when(context.getHeader("param1")).thenReturn(null); create("headers").invoke(mockController, context); verify(mockController).headers(null); } @Test public void integerParamShouldBeParsedToInteger() throws Exception { when(context.getParameter("param1")).thenReturn("20"); create("integerParam").invoke(mockController, context); verify(mockController).integerParam(20); } @Test public void integerParamShouldHandleNull() throws Exception { create("integerParam").invoke(mockController, context); verify(mockController).integerParam(null); assertFalse(validation.hasViolations()); } @Test public void integerValidationShouldWork() throws Exception { when(context.getParameter("param1")).thenReturn("blah"); create("integerParam").invoke(mockController, context); verify(mockController).integerParam(null); assertTrue(validation.hasFieldViolation("param1")); } @Test public void intParamShouldBeParsedToInteger() throws Exception { when(context.getParameter("param1")).thenReturn("20"); create("intParam").invoke(mockController, context); verify(mockController).intParam(20); } @Test public void intParamShouldHandleNull() throws Exception { create("intParam").invoke(mockController, context); verify(mockController).intParam(0); assertFalse(validation.hasViolations()); } @Test public void intValidationShouldWork() throws Exception { when(context.getParameter("param1")).thenReturn("blah"); create("intParam").invoke(mockController, context); verify(mockController).intParam(0); assertTrue(validation.hasFieldViolation("param1")); } @Test public void shortParamShouldBeParsedToShort() throws Exception { when(context.getParameter("param1")).thenReturn("20"); create("shortParam").invoke(mockController, context); verify(mockController).shortParam((short) 20); } @Test public void shortParamShouldHandleNull() throws Exception { create("shortParam").invoke(mockController, context); verify(mockController).shortParam(null); assertFalse(validation.hasViolations()); } @Test public void shortValidationShouldWork() throws Exception { when(context.getParameter("param1")).thenReturn("blah"); create("shortParam").invoke(mockController, context); verify(mockController).shortParam(null); assertTrue(validation.hasFieldViolation("param1")); } @Test public void primShortParamShouldBeParsedToShort() throws Exception { when(context.getParameter("param1")).thenReturn("20"); create("primShortParam").invoke(mockController, context); verify(mockController).primShortParam((short) 20); } @Test public void primShortParamShouldHandleNull() throws Exception { create("primShortParam").invoke(mockController, context); verify(mockController).primShortParam((short) 0); assertFalse(validation.hasViolations()); } @Test public void primShortValidationShouldWork() throws Exception { when(context.getParameter("param1")).thenReturn("blah"); create("primShortParam").invoke(mockController, context); verify(mockController).primShortParam((short) 0); assertTrue(validation.hasFieldViolation("param1")); } @Test public void characterParamShouldBeParsedToCharacter() throws Exception { when(context.getParameter("param1")).thenReturn("ABC"); create("characterParam").invoke(mockController, context); verify(mockController).characterParam('A'); } @Test public void characterParamShouldHandleNull() throws Exception { create("characterParam").invoke(mockController, context); verify(mockController).characterParam(null); assertFalse(validation.hasViolations()); } @Test public void charParamShouldBeParsedToCharacter() throws Exception { when(context.getParameter("param1")).thenReturn("ABC"); create("charParam").invoke(mockController, context); verify(mockController).charParam('A'); } @Test public void charParamShouldHandleNull() throws Exception { create("charParam").invoke(mockController, context); verify(mockController).charParam('\0'); assertFalse(validation.hasViolations()); } @Test public void byteParamShouldBeParsedToByte() throws Exception { when(context.getParameter("param1")).thenReturn("20"); create("byteParam").invoke(mockController, context); verify(mockController).byteParam((byte) 20); } @Test public void byteParamShouldHandleNull() throws Exception { create("byteParam").invoke(mockController, context); verify(mockController).byteParam(null); assertFalse(validation.hasViolations()); } @Test public void byteValidationShouldWork() throws Exception { when(context.getParameter("param1")).thenReturn("blah"); create("byteParam").invoke(mockController, context); verify(mockController).byteParam(null); assertTrue(validation.hasFieldViolation("param1")); } @Test public void primByteParamShouldBeParsedToByte() throws Exception { when(context.getParameter("param1")).thenReturn("20"); create("primByteParam").invoke(mockController, context); verify(mockController).primByteParam((byte) 20); } @Test public void primByteParamShouldHandleNull() throws Exception { create("primByteParam").invoke(mockController, context); verify(mockController).primByteParam((byte) 0); assertFalse(validation.hasViolations()); } @Test public void primByteValidationShouldWork() throws Exception { when(context.getParameter("param1")).thenReturn("blah"); create("primByteParam").invoke(mockController, context); verify(mockController).primByteParam((byte) 0); assertTrue(validation.hasFieldViolation("param1")); } @Test public void booleanParamShouldBeParsedToBoolean() throws Exception { when(context.getParameter("param1")).thenReturn("true"); create("booleanParam").invoke(mockController, context); verify(mockController).booleanParam(true); } @Test public void booleanParamShouldHandleNull() throws Exception { create("booleanParam").invoke(mockController, context); verify(mockController).booleanParam(null); assertFalse(validation.hasViolations()); } @Test(expected = BadRequestException.class) public void booleanParamShouldHandleNullInStrictMode() throws Exception { when(context.getParameter("param1")).thenReturn(null); when(ninjaProperties.getBooleanWithDefault(NinjaConstant.NINJA_STRICT_ARGUMENT_EXTRACTORS, false)).thenReturn(true); create("booleanParam").invoke(mockController, context); } @Test(expected = BadRequestException.class) public void booleanParamShouldHandleWrongInputForBooleanInStrictMode() throws Exception { when(context.getParameter("param1")).thenReturn("test"); when(ninjaProperties.getBooleanWithDefault(NinjaConstant.NINJA_STRICT_ARGUMENT_EXTRACTORS, false)).thenReturn(true); create("booleanParam").invoke(mockController, context); } @Test public void primBooleanParamShouldBeParsedToBoolean() throws Exception { when(context.getParameter("param1")).thenReturn("true"); create("primBooleanParam").invoke(mockController, context); verify(mockController).primBooleanParam(true); } @Test public void primBooleanParamShouldHandleNull() throws Exception { create("primBooleanParam").invoke(mockController, context); verify(mockController).primBooleanParam(false); assertFalse(validation.hasViolations()); } @Test public void booleanParamWithOptionalShouldHandleWrongInputForBooleanInStrictMode() throws Exception { when(context.getParameter("param1")).thenReturn("test"); when(ninjaProperties.getBooleanWithDefault(NinjaConstant.NINJA_STRICT_ARGUMENT_EXTRACTORS, false)).thenReturn(true); create("booleanParamWithOptional").invoke(mockController, context); verify(mockController).booleanParamWithOptional(Optional.empty()); } @Test public void booleanParamWithOptionalShouldHandleTrueInStrictMode() throws Exception { when(context.getParameter("param1")).thenReturn("true"); when(ninjaProperties.getBooleanWithDefault(NinjaConstant.NINJA_STRICT_ARGUMENT_EXTRACTORS, false)).thenReturn(true); create("booleanParamWithOptional").invoke(mockController, context); verify(mockController).booleanParamWithOptional(Optional.of(Boolean.TRUE)); } @Test public void booleanParamWithOptionalShouldHandleFalseInStrictMode() throws Exception { when(context.getParameter("param1")).thenReturn("false"); when(ninjaProperties.getBooleanWithDefault(NinjaConstant.NINJA_STRICT_ARGUMENT_EXTRACTORS, false)).thenReturn(true); create("booleanParamWithOptional").invoke(mockController, context); verify(mockController).booleanParamWithOptional(Optional.of(Boolean.FALSE)); } @Test public void longParamShouldBeParsedToLong() throws Exception { when(context.getParameter("param1")).thenReturn("20"); create("longParam").invoke(mockController, context); verify(mockController).longParam(20l); } @Test public void longParamShouldHandleNull() throws Exception { create("longParam").invoke(mockController, context); verify(mockController).longParam(null); assertFalse(validation.hasViolations()); } @Test public void longValidationShouldWork() throws Exception { when(context.getParameter("param1")).thenReturn("blah"); create("longParam").invoke(mockController, context); verify(mockController).longParam(null); assertTrue(validation.hasFieldViolation("param1")); } @Test public void primLongParamShouldBeParsedToLong() throws Exception { when(context.getParameter("param1")).thenReturn("20"); create("primLongParam").invoke(mockController, context); verify(mockController).primLongParam(20); } @Test public void primLongParamShouldHandleNull() throws Exception { create("primLongParam").invoke(mockController, context); verify(mockController).primLongParam(0); assertFalse(validation.hasViolations()); } @Test public void primLongValidationShouldWork() throws Exception { when(context.getParameter("param1")).thenReturn("blah"); create("primLongParam").invoke(mockController, context); verify(mockController).primLongParam(0L); assertTrue(validation.hasFieldViolation("param1")); } @Test public void floatParamShouldBeParsedToFloat() throws Exception { when(context.getParameter("param1")).thenReturn("3.14"); create("floatParam").invoke(mockController, context); verify(mockController).floatParam(3.14f); } @Test public void floatParamShouldHandleNull() throws Exception { create("floatParam").invoke(mockController, context); verify(mockController).floatParam(null); assertFalse(validation.hasViolations()); } @Test public void floatValidationShouldWork() throws Exception { when(context.getParameter("param1")).thenReturn("blah"); create("floatParam").invoke(mockController, context); verify(mockController).floatParam(null); assertTrue(validation.hasFieldViolation("param1")); } @Test public void primFloatParamShouldBeParsedToFloat() throws Exception { when(context.getParameter("param1")).thenReturn("3.14"); create("primFloatParam").invoke(mockController, context); verify(mockController).primFloatParam(3.14f); } @Test public void primFloatParamShouldHandleNull() throws Exception { create("primFloatParam").invoke(mockController, context); verify(mockController).primFloatParam(0); assertFalse(validation.hasViolations()); } @Test public void primFloatValidationShouldWork() throws Exception { when(context.getParameter("param1")).thenReturn("blah"); create("primFloatParam").invoke(mockController, context); verify(mockController).primFloatParam(0); assertTrue(validation.hasFieldViolation("param1")); } @Test public void doubleParamShouldBeParsedToDouble() throws Exception { when(context.getParameter("param1")).thenReturn("3.14"); create("doubleParam").invoke(mockController, context); verify(mockController).doubleParam(3.14); } @Test public void doubleParamShouldHandleNull() throws Exception { create("doubleParam").invoke(mockController, context); verify(mockController).doubleParam(null); assertFalse(validation.hasViolations()); } @Test public void doubleValidationShouldWork() throws Exception { when(context.getParameter("param1")).thenReturn("blah"); create("doubleParam").invoke(mockController, context); verify(mockController).doubleParam(null); assertTrue(validation.hasFieldViolation("param1")); } @Test public void primDoubleParamShouldBeParsedToDouble() throws Exception { when(context.getParameter("param1")).thenReturn("3.14"); create("primDoubleParam").invoke(mockController, context); verify(mockController).primDoubleParam(3.14); } @Test public void primDoubleParamShouldHandleNull() throws Exception { create("primDoubleParam").invoke(mockController, context); verify(mockController).primDoubleParam(0); assertFalse(validation.hasViolations()); } @Test public void primDoubleValidationShouldWork() throws Exception { when(context.getParameter("param1")).thenReturn("blah"); create("primDoubleParam").invoke(mockController, context); verify(mockController).primDoubleParam(0); assertTrue(validation.hasFieldViolation("param1")); } @Test public void enumParamShouldBeParsedToEnumCaseSensitive() throws Exception { when(context.getParameter("param1")).thenReturn("Red"); create("enumParam").invoke(mockController, context); verify(mockController).enumParam(Rainbow.Red); } @Test public void enumParamShouldBeParsedToEnumCaseInsensitive() throws Exception { when(context.getParameter("param1")).thenReturn("red"); create("enumParam").invoke(mockController, context); verify(mockController).enumParam(Rainbow.Red); } @Test public void enumParamShouldHandleNull() throws Exception { create("enumParam").invoke(mockController, context); verify(mockController).enumParam(null); assertFalse(validation.hasViolations()); } @Test public void enumParamValidationShouldWork() throws Exception { when(context.getParameter("param1")).thenReturn("blah"); create("enumParam").invoke(mockController, context); verify(mockController).enumParam(null); assertTrue(validation.hasFieldViolation("param1")); } @Test public void enumCsvParamSingleShouldBeParsed() throws Exception { when(context.getParameter("param1")).thenReturn("Red"); create("enumCsvParam").invoke(mockController, context); verify(mockController).enumCsvParam(new Rainbow[]{Rainbow.Red}); } @Test public void enumCsvParamMultipleShouldBeParsed() throws Exception { when(context.getParameter("param1")).thenReturn("Red,Orange,Yellow"); create("enumCsvParam").invoke(mockController, context); verify(mockController).enumCsvParam(new Rainbow[]{Rainbow.Red, Rainbow.Orange, Rainbow.Yellow}); } @Test public void enumCsvParamShouldReturnNull() throws Exception { when(context.getParameter("param1")).thenReturn(""); create("enumCsvParam").invoke(mockController, context); verify(mockController).enumCsvParam(null); assertFalse(validation.hasFieldViolation("param1")); } @Test public void enumCsvParamValidationShouldWork() throws Exception { when(context.getParameter("param1")).thenReturn("White,Black"); create("enumCsvParam").invoke(mockController, context); verify(mockController).enumCsvParam(null); assertTrue(validation.hasFieldViolation("param1")); } @Test public void enumArrayParamSingleShouldBeParsed() throws Exception { when(context.getParameterValues("param1")).thenReturn(Arrays.asList("Blue")); create("enumArrayParam").invoke(mockController, context); verify(mockController).enumArrayParam(new Rainbow[]{Rainbow.Blue}); } @Test public void enumArrayParamMultipleShouldBeParsed() throws Exception { when(context.getParameterValues("param1")).thenReturn(Arrays.asList("Blue", "Indigo", "Violet")); create("enumArrayParam").invoke(mockController, context); verify(mockController).enumArrayParam(new Rainbow[]{Rainbow.Blue, Rainbow.Indigo, Rainbow.Violet}); } @Test public void enumArrayParamShouldReturnNull() throws Exception { when(context.getParameterValues("param1")).thenReturn(new ArrayList<String>()); create("enumArrayParam").invoke(mockController, context); verify(mockController).enumArrayParam(null); assertFalse(validation.hasFieldViolation("param1")); } @Test public void enumArrayParamValidationShouldWork() throws Exception { when(context.getParameterValues("param1")).thenReturn(Arrays.asList("White", "Black")); create("enumArrayParam").invoke(mockController, context); verify(mockController).enumArrayParam(null); assertTrue(validation.hasFieldViolation("param1")); } @Test public void customDateFormatParamShouldBeParsedToDate() throws Exception { when(context.getParameter("param1")).thenReturn("15/01/2015"); create("dateParam", DateParamParser.class).invoke(mockController, context); verify(mockController).dateParam(new LocalDateTime(2015, 1, 15, 0, 0).toDate()); } @Test public void customDateFormatParamWithOptionalShouldBeParsedToDate() throws Exception { when(context.getParameter("param1")).thenReturn("15/01/2015"); create("dateParamWithOptional", DateParamParser.class).invoke(mockController, context); verify(mockController).dateParamWithOptional(Optional.of(new LocalDateTime(2015, 1, 15, 0, 0).toDate())); } @Test public void customDateFormatParamShouldHandleNull() throws Exception { create("dateParam", DateParamParser.class).invoke(mockController, context); verify(mockController).dateParam(null); assertFalse(validation.hasViolations()); } @Test public void customDateFormatParamWithOptionalShouldHandleEmpty() throws Exception { create("dateParamWithOptional", DateParamParser.class).invoke(mockController, context); verify(mockController).dateParamWithOptional(Optional.empty()); assertFalse(validation.hasViolations()); } @Test public void customDateFormatValidationShouldWork() throws Exception { when(context.getParameter("param1")).thenReturn("blah"); create("dateParam", DateParamParser.class).invoke(mockController, context); verify(mockController).dateParam(null); assertTrue(validation.hasFieldViolation("param1")); } @Test(expected = RoutingException.class) public void needingInjectionParamParserNotBinded() throws Exception { when(context.getParameter("param1")).thenReturn("hello"); create("needingInjectionParamParser").invoke(mockController, context); verify(mockController).needingInjectionParamParser(new Dep("hello_hello")); } @Test public void needingInjectionParamParser() throws Exception { when(context.getParameter("param1")).thenReturn("hello"); create("needingInjectionParamParser", NeedingInjectionParamParser.class).invoke(mockController, context); verify(mockController).needingInjectionParamParser(new Dep("hello_hello")); } @Test public void needingInjectionParamParserArray() throws Exception { when(context.getParameterValues("param1")).thenReturn(Arrays.asList("hello1", "hello2")); create("needingInjectionParamParserArray", NeedingInjectionParamParser.class).invoke(mockController, context); verify(mockController).needingInjectionParamParserArray(new Dep[] { new Dep("hello_hello1"), new Dep("hello_hello2") }); } @Test public void customArgumentExtractorWithNoArgsShouldBeInstantiated() { create("noArgArgumentExtractor").invoke(mockController, context); verify(mockController).noArgArgumentExtractor("noargs"); } @Test public void customArgumentExtractorWithClassArgShouldBeInstantiated() { create("classArgArgumentExtractor").invoke(mockController, context); verify(mockController).classArgArgumentExtractor("java.lang.String"); } @Test public void customArgumentExtractorWithGuiceShouldBeInstantiated() { create("guiceArgumentExtractor", new Dep("dep")).invoke(mockController, context); verify(mockController).guiceArgumentExtractor("dep:bar:java.lang.String"); } @Test public void customArgumentExtractorWithOptionalAndGuiceShouldBeInstantiated() { create("guiceArgumentExtractorWithOptional", new Dep("dep")).invoke(mockController, context); verify(mockController).guiceArgumentExtractorWithOptional(Optional.of("dep:bar:java.lang.String")); } @Test public void multipleDifferentExtractorsShouldWorkFine() { when(context.getParameter("param1")).thenReturn("value"); when(context.getPathParameter("param2")).thenReturn("20"); create("multiple").invoke(mockController, context); verify(mockController).multiple("value", 20, context, session); } @Test public void validationShouldFailWhenBadRequest() { create("required").invoke(mockController, context); verify(mockController).required(null); assertTrue(validation.hasFieldViolation("param1")); } @Test public void validationShouldPassWhenGoodRequest() { when(context.getParameter("param1")).thenReturn("value"); create("required").invoke(mockController, context); verify(mockController).required("value"); assertFalse(validation.hasViolations()); } @Test public void optionalSessionParam() { when(session.get("param1")).thenReturn("value"); create("optionalSessionParam").invoke(mockController, context); verify(mockController).optionalSessionParam(Optional.of("value")); } @Test public void optionalSessionParamEmpty() { when(session.get("param1")).thenReturn(null); create("optionalSessionParam").invoke(mockController, context); verify(mockController).optionalSessionParam(Optional.empty()); } @Test(expected = BadRequestException.class) public void sessionParamStrictModeWorks() { when(ninjaProperties.getBooleanWithDefault(NinjaConstant.NINJA_STRICT_ARGUMENT_EXTRACTORS, false)).thenReturn(true); when(session.get("param1")).thenReturn(null); create("sessionParam").invoke(mockController, context); } @Test public void optionalAttribute() { Dep dep = new Dep("dep"); when(context.getAttribute("param1", Dep.class)).thenReturn(dep); create("optionalAttribute").invoke(mockController, context); verify(mockController).optionalAttribute(Optional.of(dep)); } @Test public void optionalAttributeEmpty() { when(context.getAttribute("param1", Dep.class)).thenReturn(null); create("optionalAttribute").invoke(mockController, context); verify(mockController).optionalAttribute(Optional.empty()); } @Test(expected = BadRequestException.class) public void attributeStrictModeWorks() { when(ninjaProperties.getBooleanWithDefault(NinjaConstant.NINJA_STRICT_ARGUMENT_EXTRACTORS, false)).thenReturn(true); when(context.getAttribute("param1", Dep.class)).thenReturn(null); create("attribute").invoke(mockController, context); } @Test public void optionalHeader() { when(context.getHeader("param1")).thenReturn("value"); create("optionalHeader").invoke(mockController, context); verify(mockController).optionalHeader(Optional.of("value")); } @Test public void optionalHeaderEmpty() { when(context.getHeader("param1")).thenReturn(null); create("optionalHeader").invoke(mockController, context); verify(mockController).optionalHeader(Optional.empty()); } @Test(expected = BadRequestException.class) public void headerStrictModeWorks() { when(ninjaProperties.getBooleanWithDefault(NinjaConstant.NINJA_STRICT_ARGUMENT_EXTRACTORS, false)).thenReturn(true); when(context.getHeader("param1")).thenReturn(null); create("header").invoke(mockController, context); } @Test public void optionalParam() { when(context.getParameter("param1")).thenReturn("value"); create("optionalParam").invoke(mockController, context); verify(mockController).optionalParam(Optional.of("value")); } @Test public void optionalParamEmpty() { when(context.getParameter("param1")).thenReturn(null); create("optionalParam").invoke(mockController, context); verify(mockController).optionalParam(Optional.empty()); } @Test(expected = BadRequestException.class) public void paramStrictModeWorks() { when(ninjaProperties.getBooleanWithDefault(NinjaConstant.NINJA_STRICT_ARGUMENT_EXTRACTORS, false)).thenReturn(true); when(context.getParameter("param1")).thenReturn(null); create("param").invoke(mockController, context); } @Test public void optionalIntegerParam() { when(context.getParameter("param1")).thenReturn("1"); create("optionalIntegerParam").invoke(mockController, context); verify(mockController).optionalIntegerParam(Optional.of(1)); } @Test public void optionalIntegerParamEmpty() { when(context.getParameter("param1")).thenReturn(null); create("optionalIntegerParam").invoke(mockController, context); verify(mockController).optionalIntegerParam(Optional.empty()); } @Test(expected = BadRequestException.class) public void integerParamStrictModeWorks() { when(ninjaProperties.getBooleanWithDefault(NinjaConstant.NINJA_STRICT_ARGUMENT_EXTRACTORS, false)).thenReturn(true); when(context.getParameter("param1")).thenReturn(null); create("integerParam").invoke(mockController, context); } @Test public void optionalLongParam() { when(context.getParameter("param1")).thenReturn("1"); create("optionalLongParam").invoke(mockController, context); verify(mockController).optionalLongParam(Optional.of(1L)); } @Test public void optionalLongParamEmpty() { when(context.getParameter("param1")).thenReturn(null); create("optionalLongParam").invoke(mockController, context); verify(mockController).optionalLongParam(Optional.empty()); } @Test(expected = BadRequestException.class) public void longParamEmptyStrictModeWorks() { when(ninjaProperties.getBooleanWithDefault(NinjaConstant.NINJA_STRICT_ARGUMENT_EXTRACTORS, false)).thenReturn(true); when(context.getParameter("param1")).thenReturn(null); create("longParam").invoke(mockController, context); } @Test public void optionalShortParam() { when(context.getParameter("param1")).thenReturn("1"); create("optionalShortParam").invoke(mockController, context); verify(mockController).optionalShortParam(Optional.of(new Short("1"))); } @Test public void optionalShortParamEmpty() { when(context.getParameter("param1")).thenReturn(null); create("optionalShortParam").invoke(mockController, context); verify(mockController).optionalShortParam(Optional.empty()); } @Test(expected = BadRequestException.class) public void shortParamEmptyStrictModeWorks() { when(ninjaProperties.getBooleanWithDefault(NinjaConstant.NINJA_STRICT_ARGUMENT_EXTRACTORS, false)).thenReturn(true); when(context.getParameter("param1")).thenReturn(null); create("shortParam").invoke(mockController, context); } @Test public void optionalEnumParam() { when(context.getParameter("param1")).thenReturn("red"); create("optionalEnumParam").invoke(mockController, context); verify(mockController).optionalEnumParam(Optional.of(Rainbow.Red)); } @Test public void optionalEnumParamEmpty() { when(context.getParameter("param1")).thenReturn(null); create("optionalEnumParam").invoke(mockController, context); verify(mockController).optionalEnumParam(Optional.empty()); } @Test(expected = BadRequestException.class) public void rainbowParamStrictModeWorks() { when(ninjaProperties.getBooleanWithDefault(NinjaConstant.NINJA_STRICT_ARGUMENT_EXTRACTORS, false)).thenReturn(true); when(context.getParameter("param1")).thenReturn(null); create("enumParam").invoke(mockController, context); } @Captor ArgumentCaptor<Optional<Rainbow[]>> argumentCaptor; @Test public void optionalEnumArrayParam() { when(context.getParameter("param1")).thenReturn("Red,Orange,Yellow"); create("optionalEnumArrayParam").invoke(mockController, context); verify(mockController).optionalEnumArrayParam(argumentCaptor.capture()); Rainbow [] rainbows = argumentCaptor.getValue().get(); assertThat(rainbows, Matchers.arrayContaining(Rainbow.Red, Rainbow.Orange, Rainbow.Yellow)); } @Test public void optionalEnumArrayParamEmpty() { when(context.getParameter("param1")).thenReturn(null); create("optionalEnumArrayParam").invoke(mockController, context); verify(mockController).optionalEnumArrayParam(Optional.empty()); } @Test(expected = BadRequestException.class) public void rainbowArrayParamEmptyStrictModeWorks() { when(ninjaProperties.getBooleanWithDefault(NinjaConstant.NINJA_STRICT_ARGUMENT_EXTRACTORS, false)).thenReturn(true); when(context.getParameter("param1")).thenReturn(null); create("enumArrayParam").invoke(mockController, context); } @Test public void optionalDateParam() { when(context.getParameter("param1")).thenReturn("15/01/2015"); create("optionalDateParam", DateParamParser.class).invoke(mockController, context); verify(mockController).optionalDateParam(Optional.of(new LocalDateTime(2015, 1, 15, 0, 0).toDate())); } @Test public void optionalDateParamEmpty() { when(context.getParameter("param1")).thenReturn(null); create("optionalDateParam", DateParamParser.class).invoke(mockController, context); verify(mockController).optionalDateParam(Optional.empty()); } @Test(expected = BadRequestException.class) public void dateParamStrictModeWorks() { when(ninjaProperties.getBooleanWithDefault(NinjaConstant.NINJA_STRICT_ARGUMENT_EXTRACTORS, false)).thenReturn(true); when(context.getParameter("param1")).thenReturn(null); create("dateParam", DateParamParser.class).invoke(mockController, context); } @Test public void optionalBody() { Object body = new Object(); when(context.parseBody(Object.class)).thenReturn(body); create("optionalBody").invoke(mockController, context); verify(mockController).optionalBody(Optional.of(body)); } @Test public void optionalBodyEmpty() { when(context.parseBody(Object.class)).thenReturn(null); create("optionalBody").invoke(mockController, context); verify(mockController).optionalBody(Optional.empty()); } @Test(expected = BadRequestException.class) public void bodyEmptyStrictModeWorks() { when(ninjaProperties.getBooleanWithDefault(NinjaConstant.NINJA_STRICT_ARGUMENT_EXTRACTORS, false)).thenReturn(true); when(context.parseBody(Object.class)).thenReturn(null); create("body").invoke(mockController, context); } @Test public void validationShouldBeAppliedInCorrectOrderPreFail() { create("requiredInt").invoke(mockController, context); verify(mockController).requiredInt(0); assertTrue(validation.hasFieldViolation("param1")); assertEquals(1, validation.getFieldViolations("param1").size()); assertEquals("validation.required.violation", validation.getFieldViolations("param1").get(0).constraintViolation.getMessageKey()); } @Test public void validationWithOptionalShouldBeAppliedInCorrectOrderPreFail() { create("requiredIntWithOptional").invoke(mockController, context); verify(mockController).requiredIntWithOptional(Optional.empty()); assertTrue(validation.hasFieldViolation("param1")); } @Test public void validationShouldBeAppliedInCorrectOrderPostFail() { when(context.getParameter("param1")).thenReturn("5"); create("requiredInt").invoke(mockController, context); verify(mockController).requiredInt(5); assertTrue(validation.hasFieldViolation("param1")); assertEquals(1, validation.getFieldViolations("param1").size()); assertEquals("validation.number.min.violation", validation.getFieldViolations("param1").get(0).constraintViolation.getMessageKey()); } @Test public void validationWithOptionalShouldBeAppliedInCorrectOrderPostFail() { when(context.getParameter("param1")).thenReturn("5"); create("requiredIntWithOptional").invoke(mockController, context); verify(mockController).requiredIntWithOptional(Optional.of(5)); assertTrue(validation.hasFieldViolation("param1")); } @Test public void validationShouldBeAppliedInCorrectOrderPass() { when(context.getParameter("param1")).thenReturn("20"); create("requiredInt").invoke(mockController, context); verify(mockController).requiredInt(20); assertFalse(validation.hasViolations()); } @Test public void validationWithOptionalShouldBeAppliedInCorrectOrderPass() { when(context.getParameter("param1")).thenReturn("20"); create("requiredIntWithOptional").invoke(mockController, context); verify(mockController).requiredIntWithOptional(Optional.of(20)); assertFalse(validation.hasViolations()); } @Test(expected = RoutingException.class) public void invalidValidatorShouldBeFlagged() { create("badValidator").invoke(mockController, context); } @Test(expected = RoutingException.class) public void invalidValidatorWithOptionalShouldBeFlagged() { create("badValidatorWithOptional").invoke(mockController, context); } @Test(expected = RoutingException.class) public void tooManyBodiesShouldBeFlagged() { create("tooManyBodies").invoke(mockController, context); } @Test public void bodyShouldBeParsedIntoLeftOverParameter() { Object body = new Object(); when(context.parseBody(Object.class)).thenReturn(body); create("body").invoke(mockController, context); verify(mockController).body(body); } @Test public void bodyWithOptionalShouldBeParsedIntoLeftOverParameter() { Object body = new Object(); when(context.parseBody(Object.class)).thenReturn(body); create("bodyWithOptional").invoke(mockController, context); verify(mockController).bodyWithOptional(Optional.of(body)); } @Test public void bodyWithOptionalShouldBeEmptyIfNoBodyPresent() { when(context.parseBody(Object.class)).thenReturn(null); create("bodyWithOptional").invoke(mockController, context); verify(mockController).bodyWithOptional(Optional.empty()); } // JSR303Validation(@Pattern(regexp = "[a-z]*") String param1, // @Length(min = 5, max = 10) String param2, @Min(3) @Max(10) int param3); @Test public void validationPassed() { validateJSR303(buildDto("regex", "length", 5)); doCheckValidationPassed(context); } @Test public void validationWithOptionalPassed() { validateJSR303WithOptional(buildDto("regex", "length", 5)); doCheckValidationPassed(context); } private void doCheckValidationPassed(Context context) { assertFalse(context.getValidation().hasViolations()); assertFalse("Expected not to have regex violation.", context.getValidation().hasBeanViolation("regex")); } @Test public void validationFailedRegex() { validateJSR303(buildDto("regex!!!", "length", 5)); docheckValidationFailedRegex(context); } @Test public void validationWithOptionalFailedRegex() { validateJSR303WithOptional(buildDto("regex!!!", "length", 5)); docheckValidationFailedRegex(context); } private void docheckValidationFailedRegex(Context context) { assertTrue(context.getValidation().hasViolations()); assertEquals(context.getValidation().getBeanViolations().size(), 1); assertTrue("Expected to have regex violation.", context.getValidation().hasBeanViolation("regex")); assertTrue(context.getValidation().getBeanViolations().get(0).field .contentEquals("regex")); } @Test public void validationFailedLength() { validateJSR303(buildDto("regex", "length - too long", 5)); doCheckValidationFailedLength(context); } @Test public void validationWithOptionalFailedLength() { validateJSR303WithOptional(buildDto("regex", "length - too long", 5)); doCheckValidationFailedLength(context); } private void doCheckValidationFailedLength(Context context) { assertTrue(context.getValidation().hasViolations()); assertEquals(context.getValidation().getBeanViolations().size(), 1); assertTrue("Expected to have length violation.", context.getValidation().hasBeanViolation("length")); assertTrue(context.getValidation().getBeanViolations().get(0).field .contentEquals("length")); } @Test public void validationFailedRange() { validateJSR303(buildDto("regex", "length", 25)); doCheckValidationFailedRange(context); } @Test public void validationWithOptionalFailedRange() { validateJSR303WithOptional(buildDto("regex", "length", 25)); doCheckValidationFailedRange(context); } private void doCheckValidationFailedRange(Context context) { assertTrue(context.getValidation().hasViolations()); assertEquals(context.getValidation().getBeanViolations().size(), 1); assertTrue("Expected to have range violation.", context.getValidation().hasBeanViolation("range")); assertTrue(context.getValidation().getBeanViolations().get(0).field .contentEquals("range")); } @Test public void validationFailedTranslationFr() { when(this.context.getAcceptLanguage()).thenReturn("fr"); validateJSR303(buildDto("regex", "length - too long", 5)); doCheckValidationFailedTranslationFr(context); } @Test public void validationWithOptionalFailedTranslationFr() { when(this.context.getAcceptLanguage()).thenReturn("fr"); validateJSR303WithOptional(buildDto("regex", "length - too long", 5)); doCheckValidationFailedTranslationFr(context); } private void doCheckValidationFailedTranslationFr(Context context) { assertTrue(this.context.getValidation().hasViolations()); assertEquals(this.context.getValidation().getBeanViolations().size(), 1); assertEquals(this.context.getValidation().getBeanViolations().get(0).constraintViolation.getMessageKey(), "la taille doit ĂȘtre entre 5 et 10"); } @Test public void validationFailedTranslationEn() { when(this.context.getAcceptLanguage()).thenReturn("en"); validateJSR303(buildDto("regex", "length - too long", 5)); doCheckValidationFailedTranslationEn(context); } @Test public void validationWithOptionalFailedTranslationEn() { when(this.context.getAcceptLanguage()).thenReturn("en"); validateJSR303WithOptional(buildDto("regex", "length - too long", 5)); doCheckValidationFailedTranslationEn(context); } private void doCheckValidationFailedTranslationEn(Context context) { assertTrue(context.getValidation().hasViolations()); assertEquals(context.getValidation().getBeanViolations().size(), 1); assertEquals(context.getValidation().getBeanViolations().get(0).constraintViolation.getMessageKey(), "size must be between 5 and 10"); } @Test public void validationFailedWithThreeFields() { validateJSR303(buildDto("regex!!!", "length is now tooooo loooong", 25)); doCheckValidationFailedWithThreeFields(context); } @Test public void validationWithOptionalFailedWithThreeFields() { validateJSR303WithOptional(buildDto("regex!!!", "length is now tooooo loooong", 25)); doCheckValidationFailedWithThreeFields(context); } private void doCheckValidationFailedWithThreeFields(Context context) { assertTrue(context.getValidation().hasViolations()); assertTrue(context.getValidation().hasBeanViolations()); assertTrue("Expected to have regex violation.", context.getValidation().hasBeanViolation("regex")); assertEquals(context.getValidation().getBeanViolations().size(), 3); for (int i = 0; i < context.getValidation().getBeanViolations().size(); i++) { String fieldName = context.getValidation().getBeanViolations().get(i).field; assertTrue(fieldName.contentEquals("regex") || fieldName.contentEquals("length") || fieldName.contentEquals("range")); } } @Test public void validationFailedWithTwoAnnotations() { validateJSR303(buildDto("regex!!! which is also too long", "length", 5)); doValidationFailedWithTwoAnnotations(context); } @Test public void validationWithOptionalFailedWithTwoAnnotations() { validateJSR303WithOptional(buildDto("regex!!! which is also too long", "length", 5)); doValidationFailedWithTwoAnnotations(context); } private void doValidationFailedWithTwoAnnotations(Context context) { assertTrue(context.getValidation().hasViolations()); assertTrue(context.getValidation().hasBeanViolations()); assertEquals(context.getValidation().getBeanViolations().size(), 2); for (int i = 0; i < context.getValidation().getBeanViolations().size(); i++) { String fieldName = context.getValidation().getBeanViolations().get(i).field; assertTrue(fieldName.contentEquals("regex")); } String message0 = context.getValidation().getBeanViolations().get(0).constraintViolation .getMessageKey(); String message1 = context.getValidation().getBeanViolations().get(1).constraintViolation .getMessageKey(); assertFalse(message0.contentEquals(message1)); } @Test public void validationWithNullObject() { validateJSR303(null); assertFalse(context.getValidation().hasViolations()); validateJSR303WithOptional(null); assertFalse(context.getValidation().hasViolations()); validateJSR303WithRequired(null); assertTrue(context.getValidation().hasViolations()); } private void validateJSR303(Dto dto) { when(context.parseBody(Dto.class)).thenReturn(dto); create("JSR303Validation", this.lang).invoke(mockController, context); } private void validateJSR303WithOptional(Dto dto) { when(context.parseBody(Dto.class)).thenReturn(dto); create("JSR303ValidationWithOptional", this.lang).invoke(mockController, context); } private void validateJSR303WithRequired(Dto dto) { when(context.parseBody(Dto.class)).thenReturn(dto); create("JSR303ValidationWithRequired", this.lang).invoke(mockController, context); } private Dto buildDto(String regex, String length, int range) { Dto dto = new Dto(); dto.regex = regex; dto.length = length; dto.range = range; return dto; } private ControllerMethodInvoker create(String methodName, final Object... toBind) { Method method = null; for (Method m : MockController.class.getMethods()) { if (m.getName().equals(methodName)) { method = m; break; } } return ControllerMethodInvoker.build(method, method, Guice.createInjector(new AbstractModule() { @Override protected void configure() { Multibinder<ParamParser> parsersBinder = Multibinder.newSetBinder(binder(), ParamParser.class); bind(NinjaProperties.class).toInstance(ninjaProperties); for (Object o : toBind) { if(o instanceof Class && ParamParser.class.isAssignableFrom((Class) o)) { parsersBinder.addBinding().to((Class<? extends ParamParser>) o); } else { bind((Class<Object>) o.getClass()).toInstance(o); } } } }), ninjaProperties); } public enum Rainbow { Red, Orange, Yellow, Green, Blue, Indigo, Violet } // Custom argument extractors for testing different instantiation paths public interface MockController { public Result noParameter(); public Result context(Context context); public Result session(Session session); public Result flash(FlashScope flash); public Result param(@Param("param1") String param1); public Result pathParam(@PathParam("param1") String param1); public Result sessionParam(@SessionParam("param1") String param1); public Result attribute(@Attribute("param1") Dep param1); public Result header(@Header("param1") String param1); public Result headers(@Headers("param1") String[] param1); public Result integerParam(@Param("param1") Integer param1); public Result intParam(@Param("param1") int param1); public Result shortParam(@Param("param1") Short param1); public Result primShortParam(@Param("param1") short param1); public Result characterParam(@Param("param1") Character param1); public Result charParam(@Param("param1") char param1); public Result byteParam(@Param("param1") Byte param1); public Result primByteParam(@Param("param1") byte param1); public Result booleanParam(@Param("param1") Boolean param1); public Result booleanParamWithOptional(@Param("param1") Optional<Boolean> param1); public Result primBooleanParam(@Param("param1") boolean param1); public Result longParam(@Param("param1") Long param1); public Result primLongParam(@Param("param1") long param1); public Result floatParam(@Param("param1") Float param1); public Result primFloatParam(@Param("param1") float param1); public Result doubleParam(@Param("param1") Double param1); public Result primDoubleParam(@Param("param1") double param1); public Result enumParam(@Param("param1") Rainbow param1); public Result enumCsvParam(@Param("param1") Rainbow[] param1); public Result enumArrayParam(@Params("param1") Rainbow[] param1); public Result noArgArgumentExtractor(@NoArg String param1); public Result classArgArgumentExtractor(@ClassArg String param1); public Result guiceArgumentExtractor(@GuiceAnnotation(foo = "bar") String param1); public Result guiceArgumentExtractorWithOptional(@GuiceAnnotation(foo = "bar") Optional<String> param1); public Result multiple(@Param("param1") String param1, @PathParam("param2") int param2, Context context, Session session); public Result required(@Param("param1") @Required String param1); public Result optionalSessionParam(@SessionParam("param1") Optional<String> param1); public Result optionalAttribute(@Attribute("param1") Optional<Dep> param1); public Result optionalHeader(@Header("param1") Optional<String> param1); public Result optionalHeaders(@Headers("param1") Optional<String[]> param1); public Result optionalParam(@Param("param1") Optional<String> param1); public Result optionalIntegerParam(@Param("param1") Optional<Integer> param1); public Result optionalLongParam(@Param("param1") Optional<Long> param1); public Result optionalShortParam(@Param("param1") Optional<Short> param1); public Result optionalEnumParam(@Param("param1") Optional<Rainbow> param1); public Result optionalEnumArrayParam(@Param("param1") Optional<Rainbow[]> param1); public Result optionalDateParam(@Param("param1") Optional<Date> param1); public Result optionalBody(Optional<Object> body); public Result requiredInt(@Param("param1") @Required @NumberValue(min = 10) int param1); public Result requiredIntWithOptional(@Param("param1") @Required @NumberValue(min = 10) Optional<Integer> param1); public Result badValidator(@Param("param1") @NumberValue(min = 10) String param1); public Result badValidatorWithOptional(@Param("param1") @NumberValue(min = 10) Optional<String> param1); public Result body(Object body); public Result bodyWithOptional(Optional<Object> body); public Result tooManyBodies(Object body1, Object body2); public Result JSR303Validation(@JSR303Validation Dto dto, Validation validation); public Result JSR303ValidationWithOptional(@JSR303Validation Optional<Dto> dto, Validation validation); public Result JSR303ValidationWithRequired(@Required @JSR303Validation Dto dto, Validation validation); public Result dateParam(@Param("param1") Date param1); public Result dateParamWithOptional(@Param("param1") Optional<Date> param1); public Result needingInjectionParamParser(@Param("param1") Dep param1); public Result needingInjectionParamParserArray(@Params("param1") Dep[] paramsArray); } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) @WithArgumentExtractor(NoArgArgumentExtractor.class) public @interface NoArg { } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) @WithArgumentExtractor(ClassArgArgumentExtractor.class) public @interface ClassArg { } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) @WithArgumentExtractor(GuiceArgumentExtractor.class) public @interface GuiceAnnotation { String foo(); } public static class NoArgArgumentExtractor implements ArgumentExtractor<String> { @Override public String extract(Context context) { return "noargs"; } @Override public Class<String> getExtractedType() { return String.class; } @Override public String getFieldName() { return null; } } public static class ClassArgArgumentExtractor implements ArgumentExtractor<String> { private final Class<?> clazz; public ClassArgArgumentExtractor(Class<?> clazz) { this.clazz = clazz; } @Override public String extract(Context context) { return clazz.getName(); } @Override public Class<String> getExtractedType() { return String.class; } @Override public String getFieldName() { return null; } } public static class DateParamParser implements ParamParser<Date> { public static final String DATE_FORMAT = "dd/MM/yyyy"; public static final String KEY = "validation.is.date.violation"; public static final String MESSAGE = "{0} must be a valid date"; @Override public Date parseParameter(String field, String parameterValue, Validation validation) { try { return parameterValue == null ? null : new SimpleDateFormat(DATE_FORMAT).parse(parameterValue); } catch(ParseException e) { validation.addFieldViolation(field, ConstraintViolation.createForFieldWithDefault( KEY, field, MESSAGE, parameterValue)); return null; } } @Override public Class<Date> getParsedType() { return Date.class; } } public static class NeedingInjectionParamParser implements ParamParser<Dep> { // In a real application, you can also use @Named as each properties is binded by its name @Inject NinjaProperties properties; @Override public Dep parseParameter(String field, String parameterValue, Validation validation) { return new Dep(properties.get("needingInjectionParamParser.value") + "_" + parameterValue); } @Override public Class<Dep> getParsedType() { return Dep.class; } } /** * Argument extractor that has a complex constructor for Guice. It depends on some * other dependency (dep), plus the annotation that was on the parameter, and the * class of the parameter. */ public static class GuiceArgumentExtractor implements ArgumentExtractor<String> { private final Dep dep; private final GuiceAnnotation annot; private final Class clazz; @Inject public GuiceArgumentExtractor(Dep dep, GuiceAnnotation annot, ArgumentClassHolder holder) { this.dep = dep; this.annot = annot; this.clazz = holder.getArgumentClass(); } @Override public String extract(Context context) { return dep.value() + ":" + annot.foo() + ":" + clazz.getName(); } @Override public Class<String> getExtractedType() { return String.class; } @Override public String getFieldName() { return null; } } public static class Dep { private final String value; public Dep(String value) { this.value = value; } public String value() { return value; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((value == null) ? 0 : value.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Dep other = (Dep) obj; if (value == null) { if (other.value != null) return false; } else if (!value.equals(other.value)) return false; return true; } } public class Dto { @Size(min = 1, max = 10) @Pattern(regexp = "[a-z]*") public String regex; @Size(min = 5, max = 10) public String length; @Min(value = 3) @Max(value = 10) public int range; } }