├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── main ├── java │ └── org │ │ └── springframework │ │ └── scala │ │ └── beans │ │ ├── ScalaBeanInfo.java │ │ ├── ScalaBeanInfoFactory.java │ │ └── factory │ │ └── function │ │ └── Function0Wrapper.java ├── resources │ ├── META-INF │ │ ├── spring.factories │ │ ├── spring.handlers │ │ └── spring.schemas │ └── org │ │ └── springframework │ │ └── scala │ │ └── beans │ │ └── factory │ │ └── xml │ │ └── scala-util-1.0.xsd └── scala │ └── org │ └── springframework │ └── scala │ ├── aop │ └── AdviceConversions.scala │ ├── beans │ ├── factory │ │ ├── BeanFactoryConversions.scala │ │ ├── RichBeanFactory.scala │ │ ├── RichListableBeanFactory.scala │ │ ├── annotation │ │ │ └── ConstructorAutowiredAnnotationBeanPostProcessor.scala │ │ ├── config │ │ │ ├── Function0FactoryBean.scala │ │ │ ├── MapFactoryBean.scala │ │ │ ├── SeqFactoryBean.scala │ │ │ └── SetFactoryBean.scala │ │ ├── function │ │ │ ├── FunctionalBeanDefinition.scala │ │ │ ├── FunctionalRootBeanDefinition.scala │ │ │ └── InitDestroyFunctionBeanPostProcessor.scala │ │ └── xml │ │ │ └── UtilNamespaceHandler.scala │ └── propertyeditors │ │ ├── RegexEditor.scala │ │ ├── ScalaCollectionEditor.scala │ │ └── ScalaEditorRegistrar.scala │ ├── context │ ├── ApplicationContextConversions.scala │ ├── ApplicationListenerAdapter.scala │ ├── RichApplicationContext.scala │ └── function │ │ ├── BeanLookupFunction.scala │ │ ├── ContextSupport.scala │ │ ├── FunctionalConfigApplicationContext.scala │ │ └── FunctionalConfiguration.scala │ ├── http │ └── converter │ │ └── xml │ │ └── ElemMessageConverter.scala │ ├── jdbc │ └── core │ │ ├── JdbcCallbackConversions.scala │ │ └── JdbcTemplate.scala │ ├── jms │ └── core │ │ └── JmsTemplate.scala │ ├── test │ └── context │ │ ├── FunctionalConfigContextLoader.scala │ │ └── FunctionalConfigurations.scala │ ├── transaction │ ├── function │ │ ├── TransactionMode.scala │ │ └── TransactionSupport.scala │ └── support │ │ ├── SynchronizationEvent.scala │ │ ├── TransactionManagement.scala │ │ ├── TransactionSynchronizationManager.scala │ │ └── TransactionTemplate.scala │ ├── util │ └── TypeTagUtils.scala │ └── web │ └── client │ └── RestTemplate.scala └── test ├── java └── org │ └── springframework │ └── scala │ └── context │ └── function │ └── MyAnnotatedConfiguration.java ├── resources ├── data.sql ├── log4j.properties ├── org │ └── springframework │ │ └── scala │ │ ├── beans │ │ ├── factory │ │ │ └── xml │ │ │ │ └── utilNamespaceHandlerTest.xml │ │ ├── propertyeditors │ │ │ └── scalaEditorRegistrarTest.xml │ │ └── scalaBeanInfoFactoryIntegrationTest.xml │ │ └── context │ │ └── function │ │ └── imported.xml └── schema.sql └── scala └── org └── springframework └── scala ├── aop ├── AdviceConversionsTests.scala └── MethodAdviceConfiguration.scala ├── beans ├── ScalaBean.scala ├── ScalaBeanInfoFactoryTests.scala ├── ScalaBeanInfoTests.scala ├── factory │ ├── RichBeanFactoryTests.scala │ ├── RichListableBeanFactoryTests.scala │ ├── annotation │ │ └── ConstructorAutowiredAnnotationBeanPostProcessorTests.scala │ ├── function │ │ ├── FunctionalRootBeanDefinitionTests.scala │ │ └── InitDestroyFunctionBeanPostProcessorTests.scala │ └── xml │ │ └── UtilNamespaceHandlerTests.scala └── propertyeditors │ ├── CollectionsBean.scala │ ├── PrimitivesBean.scala │ ├── ScalaCollectionEditorTests.scala │ ├── ScalaEditorRegistrarTests.scala │ └── TypesBean.scala ├── context ├── ApplicationListenerAdapterTest.scala └── function │ ├── ComponentScanTests.scala │ ├── ContextSupportTests.scala │ ├── FunctionalConfigApplicationContextTests.scala │ ├── FunctionalConfigurationTests.scala │ ├── MyFunctionalConfiguration.scala │ └── Person.scala ├── jdbc └── core │ └── JdbcTemplateTests.scala ├── test └── context │ ├── FunctionalConfigurationsTests.scala │ └── ProfiledFunctionalConfigurationsTests.scala └── transaction ├── function └── TransactionSupportTests.scala └── support ├── TransactionManagementTests.scala └── TransactionSynchronizationManagerTests.scala /.gitignore: -------------------------------------------------------------------------------- 1 | atlassian-ide-plugin.xml 2 | *.java.hsp 3 | *.sonarj 4 | *.sw* 5 | .DS_Store 6 | .settings 7 | .springBeans 8 | target 9 | .gradle 10 | build 11 | .classpath 12 | .project 13 | 14 | # IDEA metadata and output dirs 15 | *.iml 16 | *.ipr 17 | *.iws 18 | .idea 19 | out 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spring Scala is no longer actively maintained by VMware, Inc. 2 | 3 | The goal of Spring Scala is to make it easier to use the Spring framework in Scala. 4 | 5 | **Spring Scala development within Pivotal has ceased, but fortunately a member 6 | of the community - Paul Snively - has stepped up and is continuing development 7 | over at 8 | [http://hub.darcs.net/psnively/spring-scala](http://hub.darcs.net/psnively/spring-scala). 9 | Please refer to that repository instead of this one, which might be removed in the future.** 10 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'scala' 3 | apply plugin: 'idea' 4 | apply plugin: 'eclipse' 5 | 6 | apply plugin: 'propdeps' 7 | apply plugin: 'propdeps-maven' 8 | apply plugin: 'propdeps-idea' 9 | apply plugin: 'propdeps-eclipse' 10 | 11 | group 'org.springframework.scala' 12 | archivesBaseName = "spring-scala_2.11" 13 | 14 | //set Java compiler -source and -target options 15 | sourceCompatibility = '1.7' 16 | targetCompatibility = '1.7' 17 | 18 | ext { 19 | springVersion = '3.2.4.RELEASE' 20 | scalaVersion = '2.11.2' 21 | scalaLibVersion = '2.11' 22 | } 23 | 24 | repositories { 25 | maven { url "https://repo.springsource.org/libs-snapshot" } 26 | } 27 | 28 | dependencies { 29 | // Spring 30 | optional("org.springframework:spring-aop:$springVersion") 31 | compile("org.springframework:spring-core:$springVersion") 32 | compile("org.springframework:spring-beans:$springVersion") 33 | compile("org.springframework:spring-context:$springVersion") 34 | optional("org.springframework:spring-jdbc:$springVersion") 35 | optional("org.springframework:spring-jms:$springVersion") 36 | optional("org.springframework:spring-web:$springVersion") 37 | optional("org.springframework:spring-test:$springVersion") 38 | 39 | // Scala 40 | compile("org.scala-lang:scala-library:$scalaVersion") 41 | compile("org.scala-lang:scala-reflect:$scalaVersion") 42 | //needs to be as separate jar file for scala 2.11 43 | compile("org.scala-lang.modules:scala-xml_$scalaLibVersion:1.0.2") 44 | 45 | // Jackson 46 | optional("com.fasterxml.jackson.module:jackson-module-scala_$scalaLibVersion:2.4.2") 47 | 48 | // Java EE 49 | provided("org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1") 50 | provided("javax.servlet:servlet-api:2.5") 51 | provided("javax.inject:javax.inject:1") 52 | 53 | // Test 54 | testCompile("org.scalatest:scalatest_$scalaLibVersion:2.2.2") 55 | testCompile("junit:junit:4.10") 56 | testRuntime("org.hsqldb:hsqldb-j5:2.2.4") 57 | testRuntime("log4j:log4j:1.2.16") 58 | testCompile("org.springframework:spring-aspects:$springVersion") 59 | } 60 | 61 | //Java compiler settings 62 | tasks.withType(JavaCompile) { 63 | //ignore conjunction warning 64 | options.compilerArgs << '-Xlint:-options' 65 | } 66 | 67 | tasks.withType(ScalaCompile) { 68 | scalaCompileOptions.additionalParameters = ["-feature", "-language:implicitConversions", "-language:reflectiveCalls"] 69 | scalaCompileOptions.useAnt = false 70 | } 71 | 72 | task wrapper(type: Wrapper) { 73 | description = 'Generates gradlew[.bat] scripts' 74 | gradleVersion = '1.12' 75 | } 76 | 77 | buildscript { 78 | repositories { 79 | maven { url 'https://repo.springsource.org/plugins-release' } 80 | } 81 | dependencies { 82 | classpath 'org.springframework.build.gradle:propdeps-plugin:0.0.7' 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | version=1.0.0.BUILD-SNAPSHOT 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-attic/spring-scala/19836f1df1ff4bb1746633e3112bc8884064c65b/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Sep 16 13:59:05 CEST 2014 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-1.12-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'spring-scala' 2 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/scala/beans/ScalaBeanInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans; 18 | 19 | import java.awt.Image; 20 | import java.beans.BeanDescriptor; 21 | import java.beans.BeanInfo; 22 | import java.beans.EventSetDescriptor; 23 | import java.beans.IntrospectionException; 24 | import java.beans.Introspector; 25 | import java.beans.MethodDescriptor; 26 | import java.beans.PropertyDescriptor; 27 | import java.lang.reflect.Method; 28 | import java.util.Comparator; 29 | import java.util.Map; 30 | import java.util.TreeMap; 31 | 32 | import org.apache.commons.logging.Log; 33 | import org.apache.commons.logging.LogFactory; 34 | 35 | import org.springframework.util.Assert; 36 | import org.springframework.util.ReflectionUtils; 37 | 38 | /** 39 | * Implementation of {@link BeanInfo} for Scala classes. Decorates a standard {@link 40 | * BeanInfo} object by including Scala setter methods (ending in {@code _$eq} in the 41 | * collection of {@linkplain #getPropertyDescriptors() property descriptors}. 42 | * 43 | * @author Arjen Poutsma 44 | */ 45 | class ScalaBeanInfo implements BeanInfo { 46 | 47 | private static final Log logger = LogFactory.getLog(ScalaBeanInfo.class); 48 | 49 | private static final String SCALA_SETTER_SUFFIX = "_$eq"; 50 | 51 | private final BeanInfo delegate; 52 | 53 | private final PropertyDescriptor[] propertyDescriptors; 54 | 55 | public ScalaBeanInfo(Class beanClass) throws IntrospectionException { 56 | this(Introspector.getBeanInfo(beanClass)); 57 | } 58 | 59 | public ScalaBeanInfo(BeanInfo delegate) throws IntrospectionException { 60 | Assert.notNull(delegate, "'delegate' must not be null"); 61 | this.delegate = delegate; 62 | this.propertyDescriptors = initPropertyDescriptors(delegate); 63 | } 64 | 65 | private static PropertyDescriptor[] initPropertyDescriptors(BeanInfo beanInfo) { 66 | Map propertyDescriptors = 67 | new TreeMap(new PropertyNameComparator()); 68 | for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) { 69 | propertyDescriptors.put(pd.getName(), pd); 70 | } 71 | 72 | for (MethodDescriptor md : beanInfo.getMethodDescriptors()) { 73 | Method method = md.getMethod(); 74 | 75 | if (ReflectionUtils.isObjectMethod(method)) { 76 | continue; 77 | } 78 | if (isScalaSetter(method)) { 79 | addScalaSetter(propertyDescriptors, method); 80 | } 81 | else if (isScalaGetter(method)) { 82 | addScalaGetter(propertyDescriptors, method); 83 | } 84 | } 85 | return propertyDescriptors.values() 86 | .toArray(new PropertyDescriptor[propertyDescriptors.size()]); 87 | } 88 | 89 | private static boolean isScalaGetter(Method method) { 90 | return method.getParameterTypes().length == 0 && 91 | !method.getReturnType().equals(Void.TYPE) && 92 | !(method.getName().startsWith("get") || 93 | method.getName().startsWith("is")); 94 | } 95 | 96 | public static boolean isScalaSetter(Method method) { 97 | return method.getParameterTypes().length == 1 && 98 | method.getReturnType().equals(Void.TYPE) && 99 | method.getName().endsWith(SCALA_SETTER_SUFFIX); 100 | } 101 | 102 | private static void addScalaSetter(Map propertyDescriptors, 103 | Method writeMethod) { 104 | String propertyName = writeMethod.getName().substring(0, 105 | writeMethod.getName().length() - SCALA_SETTER_SUFFIX.length()); 106 | 107 | PropertyDescriptor pd = propertyDescriptors.get(propertyName); 108 | if (pd != null && pd.getWriteMethod() == null) { 109 | try { 110 | pd.setWriteMethod(writeMethod); 111 | } 112 | catch (IntrospectionException ex) { 113 | logger.debug("Could not add write method [" + writeMethod + "] for " + 114 | "property [" + propertyName + "]: " + ex.getMessage()); 115 | } 116 | } 117 | else if (pd == null) { 118 | try { 119 | pd = new PropertyDescriptor(propertyName, null, writeMethod); 120 | propertyDescriptors.put(propertyName, pd); 121 | } 122 | catch (IntrospectionException ex) { 123 | logger.debug("Could not create new PropertyDescriptor for " + 124 | "writeMethod [" + writeMethod + "] property [" + propertyName + 125 | "]: " + ex.getMessage()); 126 | } 127 | } 128 | } 129 | 130 | private static void addScalaGetter(Map propertyDescriptors, 131 | Method readMethod) { 132 | String propertyName = readMethod.getName(); 133 | 134 | PropertyDescriptor pd = propertyDescriptors.get(propertyName); 135 | if (pd != null && pd.getReadMethod() == null) { 136 | try { 137 | pd.setReadMethod(readMethod); 138 | } 139 | catch (IntrospectionException ex) { 140 | logger.debug("Could not add read method [" + readMethod + "] for " + 141 | "property [" + propertyName + "]: " + ex.getMessage()); 142 | } 143 | } 144 | else if (pd == null) { 145 | try { 146 | pd = new PropertyDescriptor(propertyName, readMethod, null); 147 | propertyDescriptors.put(propertyName, pd); 148 | } 149 | catch (IntrospectionException ex) { 150 | logger.debug("Could not create new PropertyDescriptor for " + 151 | "readMethod [" + readMethod + "] property [" + propertyName + 152 | "]: " + ex.getMessage()); 153 | } 154 | } 155 | } 156 | 157 | public PropertyDescriptor[] getPropertyDescriptors() { 158 | return propertyDescriptors; 159 | } 160 | 161 | public BeanInfo[] getAdditionalBeanInfo() { 162 | return delegate.getAdditionalBeanInfo(); 163 | } 164 | 165 | public BeanDescriptor getBeanDescriptor() { 166 | return delegate.getBeanDescriptor(); 167 | } 168 | 169 | public int getDefaultEventIndex() { 170 | return delegate.getDefaultEventIndex(); 171 | } 172 | 173 | public int getDefaultPropertyIndex() { 174 | return delegate.getDefaultPropertyIndex(); 175 | } 176 | 177 | public EventSetDescriptor[] getEventSetDescriptors() { 178 | return delegate.getEventSetDescriptors(); 179 | } 180 | 181 | public Image getIcon(int iconKind) { 182 | return delegate.getIcon(iconKind); 183 | } 184 | 185 | public MethodDescriptor[] getMethodDescriptors() { 186 | return delegate.getMethodDescriptors(); 187 | } 188 | 189 | /** 190 | * Sorts property names alphanumerically to emulate the behavior of {@link 191 | * java.beans.BeanInfo#getPropertyDescriptors()}. 192 | */ 193 | private static class PropertyNameComparator implements Comparator { 194 | 195 | public int compare(String left, String right) { 196 | byte[] leftBytes = left.getBytes(); 197 | byte[] rightBytes = right.getBytes(); 198 | 199 | for (int i = 0; i < left.length(); i++) { 200 | if (right.length() == i) { 201 | return 1; 202 | } 203 | int result = leftBytes[i] - rightBytes[i]; 204 | if (result != 0) { 205 | return result; 206 | } 207 | } 208 | return left.length() - right.length(); 209 | } 210 | } 211 | 212 | } 213 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/scala/beans/ScalaBeanInfoFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans; 18 | 19 | import java.beans.BeanInfo; 20 | import java.beans.IntrospectionException; 21 | import java.lang.reflect.Method; 22 | 23 | import org.springframework.beans.BeanInfoFactory; 24 | import org.springframework.core.Ordered; 25 | 26 | /** 27 | * Implementation of the {@code BeanInfoFactory} interface for Scala beans. 28 | * 29 | *

The {@link BeanInfo} returned from {@link #getBeanInfo(Class)} includes {@linkplain 30 | * java.beans.BeanInfo#getPropertyDescriptors() property descriptors} for "normal" 31 | * JavaBean properties as well as Scala properties (i.e. setter methods that end with 32 | * {@code _$eq}). 33 | * 34 | * @author Arjen Poutsma 35 | */ 36 | public class ScalaBeanInfoFactory implements BeanInfoFactory, Ordered { 37 | 38 | @Override 39 | public BeanInfo getBeanInfo(Class beanClass) throws IntrospectionException { 40 | return supports(beanClass) ? new ScalaBeanInfo(beanClass) : null; 41 | 42 | } 43 | 44 | private boolean supports(Class beanClass) { 45 | for (Method method : beanClass.getMethods()) { 46 | if (ScalaBeanInfo.isScalaSetter(method)) { 47 | return true; 48 | } 49 | } 50 | return false; 51 | } 52 | 53 | @Override 54 | public int getOrder() { 55 | return Ordered.LOWEST_PRECEDENCE - 1000; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/scala/beans/factory/function/Function0Wrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory.function; 18 | 19 | import scala.Function0; 20 | 21 | /** 22 | * Simple static wrapper for a Scala {@link Function0}. 23 | *

24 | * Used by the {@link FunctionalRootBeanDefinition} as a provider of a static 25 | * factory method. In Java, because the Spring bean factory natively does not handle Scala 26 | * Objects well. 27 | * 28 | * @author Arjen Poutsma 29 | * @see FunctionalRootBeanDefinition 30 | */ 31 | public class Function0Wrapper { 32 | 33 | private Function0Wrapper() { 34 | } 35 | 36 | public static T apply(Function0 function) { 37 | return function.apply(); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.beans.BeanInfoFactory=org.springframework.scala.beans.ScalaBeanInfoFactory -------------------------------------------------------------------------------- /src/main/resources/META-INF/spring.handlers: -------------------------------------------------------------------------------- 1 | http\://www.springframework.org/schema/scala/util=org.springframework.scala.beans.factory.xml.UtilNamespaceHandler 2 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/spring.schemas: -------------------------------------------------------------------------------- 1 | http\://www.springframework.org/schema/scala/util/scala-util-1.0.xsd=org/springframework/scala/beans/factory/xml/scala-util-1.0.xsd 2 | http\://www.springframework.org/schema/scala/util/scala-util.xsd=org/springframework/scala/beans/factory/xml/scala-util-1.0.xsd 3 | -------------------------------------------------------------------------------- /src/main/resources/org/springframework/scala/beans/factory/xml/scala-util-1.0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Builds a Seq instance of the specified type, populated with the specified content. 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 40 | 41 | 42 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | Builds a Set instance of the specified type, populated with the specified content. 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 83 | 84 | 85 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | Builds a Map instance of the specified type, populated with the specified content. 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 126 | 127 | 128 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/aop/AdviceConversions.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.aop 18 | 19 | import org.springframework.aop.{AfterReturningAdvice, MethodBeforeAdvice} 20 | import java.lang.reflect.Method 21 | import org.aopalliance.intercept.{MethodInvocation, MethodInterceptor} 22 | 23 | /** 24 | * A collection of implicit conversions between functions and Spring AOP advice. 25 | * 26 | * @author Henryk Konsek 27 | * @author Arjen Poutsma 28 | */ 29 | object AdviceConversions { 30 | 31 | /** 32 | * Implicitly converts an advice function to a [[org.aopalliance.intercept.MethodInterceptor]]. 33 | * 34 | * @param advice the function to be converted 35 | * @return the method interceptor 36 | */ 37 | implicit def asMethodInterceptor(advice: MethodInvocation => AnyRef): MethodInterceptor = { 38 | new MethodInterceptor { 39 | def invoke(invocation: MethodInvocation) = advice(invocation) 40 | } 41 | } 42 | 43 | /** 44 | * Implicitly converts an advice function to a [[org.springframework.aop.MethodBeforeAdvice]]. 45 | * 46 | * @param advice the function to be converted 47 | * @return the method before advice 48 | */ 49 | implicit def asMethodBeforeAdvice(advice: (Method, Array[AnyRef], Any) => Any): MethodBeforeAdvice = { 50 | new MethodBeforeAdvice { 51 | def before(method: Method, args: Array[AnyRef], target: Any) { 52 | advice(method, args, target) 53 | } 54 | } 55 | } 56 | 57 | /** 58 | * Implicitly converts an advice function to a [[org.springframework.aop.AfterReturningAdvice]]. 59 | * 60 | * @param advice the function to be converted 61 | * @return an after returning advice 62 | */ 63 | implicit def asAfterReturningAdvice(advice: (Any, Method, Array[AnyRef], Any) => Any): AfterReturningAdvice = { 64 | new AfterReturningAdvice { 65 | def afterReturning(returnValue: Any, method: Method, args: Array[AnyRef], target: Any) { 66 | advice(returnValue, method, args, target) 67 | } 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/beans/factory/BeanFactoryConversions.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory 18 | 19 | import org.springframework.beans.factory.{ListableBeanFactory, BeanFactory} 20 | import scala.collection.JavaConversions._ 21 | import org.springframework.scala.util.TypeTagUtils.typeToClass 22 | import scala.reflect.ClassTag 23 | 24 | /** 25 | * A collection of implicit conversions between bean factories and their rich counterpart. 26 | * 27 | * @author Arjen Poutsma 28 | */ 29 | object BeanFactoryConversions { 30 | 31 | /** 32 | * Implicitly converts a [[org.springframework.beans.factory.BeanFactory]] to a 33 | * [[org.springframework.scala.beans.factory.RichBeanFactory]]. 34 | * 35 | * @param beanFactory the bean factory to be converted 36 | * @return the rich bean factory 37 | */ 38 | implicit def toRichBeanFactory(beanFactory: BeanFactory): RichBeanFactory = 39 | new DefaultRichBeanFactory(beanFactory) 40 | 41 | /** 42 | * Implicitly converts a [[org.springframework.beans.factory.ListableBeanFactory]] to a 43 | * [[org.springframework.scala.beans.factory.RichListableBeanFactory]]. 44 | * 45 | * @param beanFactory the listable bean factory to be converted 46 | * @return the rich listable bean factory 47 | */ 48 | implicit def toRichListableBeanFactory(beanFactory: ListableBeanFactory): RichListableBeanFactory = 49 | new DefaultRichListableBeanFactory(beanFactory) 50 | 51 | } 52 | 53 | private[springframework] class DefaultRichBeanFactory(val beanFactory: BeanFactory) 54 | extends RichBeanFactory { 55 | 56 | def apply[T : ClassTag]() = { 57 | beanFactory.getBean(typeToClass[T]) 58 | } 59 | 60 | def apply[T : ClassTag](name: String) = { 61 | beanFactory.getBean(name, typeToClass[T]) 62 | } 63 | 64 | } 65 | 66 | private[springframework] class DefaultRichListableBeanFactory(beanFactory: ListableBeanFactory) 67 | extends DefaultRichBeanFactory(beanFactory) with RichListableBeanFactory { 68 | 69 | def beanNamesForType[T : ClassTag](includeNonSingletons: Boolean = true, 70 | allowEagerInit: Boolean = true): Seq[String] = { 71 | beanFactory.getBeanNamesForType(typeToClass[T], 72 | includeNonSingletons, 73 | allowEagerInit) 74 | } 75 | 76 | def beansOfType[T : ClassTag](includeNonSingletons: Boolean = true, 77 | allowEagerInit: Boolean = true): Map[String, T] = { 78 | beanFactory 79 | .getBeansOfType(typeToClass[T], includeNonSingletons, allowEagerInit) 80 | .toMap 81 | } 82 | 83 | } 84 | 85 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/beans/factory/RichBeanFactory.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory 18 | 19 | import org.springframework.beans.factory.{BeanNotOfRequiredTypeException, NoUniqueBeanDefinitionException, NoSuchBeanDefinitionException} 20 | import org.springframework.beans.BeansException 21 | import scala.reflect.ClassTag 22 | 23 | /** 24 | * Rich wrapper for [[org.springframework.beans.factory.BeanFactory]], offering 25 | * Scala-specific methods. 26 | * 27 | * @author Arjen Poutsma 28 | */ 29 | trait RichBeanFactory { 30 | 31 | /** 32 | * Optionally returns the bean instance that uniquely matches the given object type, if any. 33 | * 34 | * @tparam T type the bean must match; can be an interface or superclass. 35 | * @return an option value containing the instance of the single bean matching the required type; 36 | * or `None` if no such bean was found 37 | */ 38 | @throws(classOf[NoUniqueBeanDefinitionException]) 39 | def bean[T : ClassTag](): Option[T] = { 40 | try { 41 | Option(apply[T]()) 42 | } 43 | catch { 44 | case _: NoSuchBeanDefinitionException => None 45 | case _: NoUniqueBeanDefinitionException => None 46 | } 47 | } 48 | 49 | /** 50 | * Returns the bean instance that uniquely matches the given object type, if any. 51 | * 52 | * @tparam T type the bean must match; can be an interface or superclass. 53 | * @return an instance of the single bean matching the required type 54 | * @throws NoSuchBeanDefinitionException if no bean of the given type was found 55 | * @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found 56 | */ 57 | @throws(classOf[NoSuchBeanDefinitionException]) 58 | @throws(classOf[NoUniqueBeanDefinitionException]) 59 | def apply[T : ClassTag](): T 60 | 61 | /** 62 | * Optionally returns an instance, which may be shared or independent, of the specified 63 | * bean. 64 | * 65 | * @param name the name of the bean to retrieve 66 | * @tparam T type the bean must match. Can be an interface or superclass 67 | * of the actual class. 68 | * @return an option value containing the an instance of the bean; or `None` if no such 69 | * bean was found 70 | * @throws BeansException if the bean could not be created 71 | */ 72 | @throws(classOf[BeansException]) 73 | def bean[T : ClassTag](name: String): Option[T] = { 74 | try { 75 | Option(apply[T](name)) 76 | } 77 | catch { 78 | case _: NoSuchBeanDefinitionException => None 79 | case _: BeanNotOfRequiredTypeException => None 80 | } 81 | } 82 | 83 | /** 84 | * Return an instance, which may be shared or independent, of the specified bean. 85 | * 86 | * @param name the name of the bean to retrieve 87 | * @tparam T type the bean must match. Can be an interface or superclass 88 | * of the actual class. 89 | * @return an instance of the bean 90 | * @throws NoSuchBeanDefinitionException if there is no such bean definition 91 | * @throws BeanNotOfRequiredTypeException if the bean is not of the required type 92 | * @throws BeansException if the bean could not be created 93 | */ 94 | @throws(classOf[NoSuchBeanDefinitionException]) 95 | @throws(classOf[BeanNotOfRequiredTypeException]) 96 | @throws(classOf[BeansException]) 97 | def apply[T : ClassTag](name: String): T 98 | 99 | } -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/beans/factory/RichListableBeanFactory.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory 18 | 19 | import scala.reflect.ClassTag 20 | 21 | /** 22 | * Rich wrapper for [[org.springframework.beans.factory.ListableBeanFactory]], offering 23 | * Scala-specific methods. 24 | * 25 | * @author Arjen Poutsma 26 | */ 27 | trait RichListableBeanFactory extends RichBeanFactory { 28 | 29 | /** 30 | * Return the names of beans matching the given type (including subclasses), 31 | * judging from either bean definitions or the value of `getObjectType` 32 | * in the case of [[org.springframework.beans.factory.FactoryBean]]s. 33 | * 34 | * @note '''This method introspects top-level beans only.''' It does ''not'' 35 | * check nested beans which might match the specified type as well. 36 | * @note Does consider objects created by FactoryBeans if the `allowEagerInit` flag is set, 37 | * which means that FactoryBeans will get initialized. If the object created by the 38 | * FactoryBean doesn't match, the raw FactoryBean itself will be matched against the 39 | * type. If `allowEagerInit` is not set, only raw FactoryBeans will be checked 40 | * (which doesn't require initialization of each FactoryBean). 41 | * @note Does not consider any hierarchy this factory may participate in. 42 | * Use [[org.springframework.beans.factory.BeanFactoryUtils]]' 43 | * `beanNamesForTypeIncludingAncestors` to include beans in ancestor factories too. 44 | * @note Does ''not'' ignore singleton beans that have been registered 45 | * by other means than bean definitions. 46 | * @param includeNonSingletons whether to include prototype or scoped beans too 47 | * or just singletons (also applies to FactoryBeans). Defaults to `true`. 48 | * @param allowEagerInit whether to initialize ''lazy-init singletons'' and 49 | * ''objects created by FactoryBeans'' (or by factory methods with a 50 | * "factory-bean" reference) for the type check. Note that FactoryBeans need to be 51 | * eagerly initialized to determine their type: So be aware that passing in "true" 52 | * for this flag will initialize FactoryBeans and "factory-bean" references. Defaults to 53 | * `true`. 54 | * @tparam T the class or interface to match 55 | * @return the names of beans (or objects created by FactoryBeans) matching 56 | * the given object type (including subclasses), or an empty array if none 57 | * @see FactoryBean#getObjectType 58 | * @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, Class, boolean, boolean) 59 | */ 60 | def beanNamesForType[T : ClassTag](includeNonSingletons: Boolean = true, allowEagerInit: Boolean = true): Seq[String] 61 | 62 | /** 63 | * Return the bean instances that match the given object type (including 64 | * subclasses), judging from either bean definitions or the value of 65 | * `getObjectType` in the case of [[org.springframework.beans.factory.FactoryBean]]s. 66 | * 67 | * @note '''This method introspects top-level beans only.''' It does ''not'' 68 | * check nested beans which might match the specified type as well. 69 | * @note Does consider objects created by FactoryBeans if the `allowEagerInit` flag is set, 70 | * which means that FactoryBeans will get initialized. If the object created by the 71 | * FactoryBean doesn't match, the raw FactoryBean itself will be matched against the 72 | * type. If `allowEagerInit` is not set, only raw FactoryBeans will be checked 73 | * (which doesn't require initialization of each FactoryBean). 74 | * @note Does not consider any hierarchy this factory may participate in. 75 | * Use [[org.springframework.beans.factory.BeanFactoryUtils]]' 76 | * `beansOfTypeIncludingAncestors` to include beans in ancestor factories too. 77 | * @note Does ''not'' ignore singleton beans that have been registered by other means 78 | * than bean definitions. 79 | *

The Map returned by this method should always return bean names and 80 | * corresponding bean instances in the order of definition in the 81 | * backend configuration, as far as possible. 82 | * @tparam T the class or interface to match 83 | * @return a Map with the matching beans, containing the bean names as 84 | * keys and the corresponding bean instances as values 85 | * @throws BeansException if a bean could not be created 86 | * @see FactoryBean#getObjectType 87 | * @see BeanFactoryUtils#beansOfTypeIncludingAncestors(ListableBeanFactory, Class, boolean, boolean) 88 | */ 89 | def beansOfType[T : ClassTag]: Map[String, T] = 90 | beansOfType[T]() 91 | 92 | /** 93 | * Return the bean instances that match the given object type (including 94 | * subclasses), judging from either bean definitions or the value of 95 | * `getObjectType` in the case of [[org.springframework.beans.factory.FactoryBean]]s. 96 | * 97 | * @note '''This method introspects top-level beans only.''' It does ''not'' 98 | * check nested beans which might match the specified type as well. 99 | * @note Does consider objects created by FactoryBeans if the `allowEagerInit` flag is set, 100 | * which means that FactoryBeans will get initialized. If the object created by the 101 | * FactoryBean doesn't match, the raw FactoryBean itself will be matched against the 102 | * type. If `allowEagerInit` is not set, only raw FactoryBeans will be checked 103 | * (which doesn't require initialization of each FactoryBean). 104 | * @note Does not consider any hierarchy this factory may participate in. 105 | * Use [[org.springframework.beans.factory.BeanFactoryUtils]]' 106 | * `beansOfTypeIncludingAncestors` to include beans in ancestor factories too. 107 | * @note Does ''not'' ignore singleton beans that have been registered by other means 108 | * than bean definitions. 109 | *

The Map returned by this method should always return bean names and 110 | * corresponding bean instances in the order of definition in the 111 | * backend configuration, as far as possible. 112 | * @param includeNonSingletons whether to include prototype or scoped beans too 113 | * or just singletons (also applies to FactoryBeans). 114 | * Defaults to `true`. 115 | * @param allowEagerInit whether to initialize lazy-init singletons and 116 | * objects created by FactoryBeans (or by factory methods with a 117 | * "factory-bean" reference) for the type check. Note that FactoryBeans need to be 118 | * eagerly initialized to determine their type: So be aware that passing in "true" 119 | * for this flag will initialize FactoryBeans and "factory-bean" references. 120 | * Defaults to `true`. 121 | * @tparam T the class or interface to match 122 | * @return a Map with the matching beans, containing the bean names as 123 | * keys and the corresponding bean instances as values 124 | * @throws BeansException if a bean could not be created 125 | * @see FactoryBean#getObjectType 126 | * @see BeanFactoryUtils#beansOfTypeIncludingAncestors(ListableBeanFactory, Class, boolean, boolean) 127 | */ 128 | def beansOfType[T : ClassTag](includeNonSingletons: Boolean = true, allowEagerInit: Boolean = true) : Map[String, T] 129 | 130 | } 131 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/beans/factory/annotation/ConstructorAutowiredAnnotationBeanPostProcessor.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory.annotation 18 | 19 | import java.lang.annotation.Annotation 20 | import java.lang.reflect.Constructor 21 | import org.apache.commons.logging.{LogFactory, Log} 22 | import org.springframework.beans.factory.annotation.Autowired 23 | import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter 24 | import org.springframework.core.Ordered 25 | import org.springframework.core.annotation.AnnotationUtils 26 | import org.springframework.stereotype.Component 27 | import scala.beans.BeanProperty 28 | import scala.collection.mutable 29 | 30 | /** 31 | * Simple extension of [[org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor]] 32 | * that detects the presence of @Autowired on a class with a single constructor. 33 | * 34 | * If both conditions are met then the constructor will be marked as a candidate 35 | * constructor, equivalent to marking the constructor with @Autowired in Java. 36 | * 37 | * This allows Scala inline constructors to be eligible for autowiring using the 38 | * following natural syntax. 39 | * 40 | * {{{ 41 | * @Autowired 42 | * class MyBean(dep: MyDependency) { ... } 43 | * }}} 44 | * 45 | * @author Stephen Samuel 46 | * @author Arjen Poutsma 47 | */ 48 | @Component 49 | class ConstructorAutowiredAnnotationBeanPostProcessor 50 | extends InstantiationAwareBeanPostProcessorAdapter with Ordered { 51 | 52 | protected final val logger: Log = LogFactory.getLog(getClass) 53 | 54 | private val autowiredAnnotationTypes: mutable.Set[Class[_ <: Annotation]] = 55 | new mutable.HashSet[Class[_ <: Annotation]]() 56 | 57 | autowiredAnnotationTypes += classOf[Autowired] 58 | 59 | try { 60 | val cl = classOf[ConstructorAutowiredAnnotationBeanPostProcessor].getClassLoader 61 | autowiredAnnotationTypes += cl.loadClass("javax.inject.Inject").asInstanceOf[Class[_ <: Annotation]] 62 | logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring") 63 | } 64 | catch { 65 | case ex: ClassNotFoundException => 66 | } 67 | 68 | @BeanProperty 69 | var order: Int = org.springframework.core.Ordered.LOWEST_PRECEDENCE 70 | 71 | 72 | override def determineCandidateConstructors(beanClass: Class[_], beanName: String): Array[Constructor[_]] = { 73 | val constructors = beanClass.getDeclaredConstructors 74 | if (isAutowiredClass(beanClass) && constructors.size == 1) { 75 | constructors 76 | } else { 77 | null 78 | } 79 | } 80 | 81 | private def isAutowiredClass(beanClass: Class[_]): Boolean = 82 | autowiredAnnotationTypes.exists(AnnotationUtils.getAnnotation(beanClass, _) != null) 83 | } -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/beans/factory/config/Function0FactoryBean.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory.config 18 | 19 | import org.springframework.beans.factory.config.AbstractFactoryBean 20 | 21 | /** 22 | * Factory bean for [[scala.Function0]] functions. 23 | * 24 | * @author Arjen Poutsma 25 | * @param function the function 26 | * @param objectType the object type to be returned from ``getObjectType`` 27 | * @tparam T the return type of the function 28 | */ 29 | class Function0FactoryBean[T](function: Function0[T], objectType: Class[T]) 30 | extends AbstractFactoryBean[T] { 31 | 32 | def getObjectType = objectType 33 | 34 | def createInstance() = function() 35 | } 36 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/beans/factory/config/MapFactoryBean.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory.config 18 | 19 | import org.springframework.beans.factory.config.AbstractFactoryBean 20 | import scala.collection.{mutable, Map} 21 | 22 | /** 23 | * Simple factory for shared [[scala.collection.Map]] instances. Allows for central setup 24 | * of sequences via the "`map`" element in XML bean definitions. 25 | * 26 | * @author Arjen Poutsma 27 | * @tparam T the element type of the collection 28 | * @param sourceMap the source map, typically populated via XML "map" elements 29 | * @param builderFunction function used to create a new map builder 30 | */ 31 | class MapFactoryBean[T, U](val sourceMap: Map[T, U], 32 | val builderFunction: () => mutable.Builder[(T, U), Map[T, U]]) 33 | extends AbstractFactoryBean[scala.collection.Map[T, U]] { 34 | 35 | def this(sourceMap: Map[T, U]) { 36 | this(sourceMap, Map.newBuilder[T, U] _) 37 | } 38 | 39 | override def getObjectType = classOf[Map[T, U]] 40 | 41 | override def createInstance(): Map[T, U] = { 42 | val builder = builderFunction() 43 | // TODO: determine Seq element type by using GenericCollectionTypeResolver 44 | builder ++= sourceMap 45 | builder.result() 46 | } 47 | } -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/beans/factory/config/SeqFactoryBean.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory.config 18 | 19 | import org.springframework.beans.factory.config.AbstractFactoryBean 20 | import scala.collection.{mutable, Seq} 21 | 22 | /** 23 | * Simple factory for shared [[scala.collection.Seq]] instances. Allows for central setup 24 | * of sequences via the "`seq`" element in XML bean definitions. 25 | * 26 | * @author Arjen Poutsma 27 | * @tparam T the element type of the collection 28 | * @param sourceSeq the source sequence, typically populated via XML "seq" elements 29 | * @param builderFunction function used to create a new sequence builder 30 | */ 31 | class SeqFactoryBean[T](val sourceSeq: Seq[T], 32 | val builderFunction: () => mutable.Builder[T, Seq[T]]) 33 | extends AbstractFactoryBean[Seq[T]] { 34 | 35 | def this(sourceSeq: Seq[T]) { 36 | this(sourceSeq, Seq.newBuilder[T] _) 37 | } 38 | 39 | override def getObjectType = classOf[Seq[T]] 40 | 41 | override def createInstance(): Seq[T] = { 42 | val builder = builderFunction() 43 | // TODO: determine Seq element type by using GenericCollectionTypeResolver 44 | builder ++= sourceSeq 45 | builder.result() 46 | } 47 | } -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/beans/factory/config/SetFactoryBean.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory.config 18 | 19 | import org.springframework.beans.factory.config.AbstractFactoryBean 20 | import scala.collection.mutable 21 | 22 | /** 23 | * Simple factory for shared [[scala.collection.Set]] instances. Allows for central setup 24 | * of sequences via the "`set`" element in XML bean definitions. 25 | * 26 | * @author Arjen Poutsma 27 | * @tparam T the element type of the collection 28 | * @param sourceSet the source set, typically populated via XML "set" elements 29 | * @param builderFunction function used to create a new set builder 30 | */ 31 | class SetFactoryBean[T](val sourceSet: scala.collection.Set[T], 32 | val builderFunction: () => mutable.Builder[T, Set[T]]) 33 | extends AbstractFactoryBean[scala.collection.Set[T]] { 34 | 35 | def this(sourceSet: scala.collection.Set[T]) { 36 | this(sourceSet, scala.collection.Set.newBuilder[T] _) 37 | } 38 | 39 | override def getObjectType = classOf[scala.collection.Set[T]] 40 | 41 | override def createInstance(): scala.collection.Set[T] = { 42 | val builder = builderFunction() 43 | // TODO: determine Set element type by using GenericCollectionTypeResolver 44 | builder ++= sourceSet 45 | builder.result() 46 | } 47 | } -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/beans/factory/function/FunctionalBeanDefinition.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory.function 18 | 19 | import org.springframework.beans.factory.config.BeanDefinition 20 | 21 | /** 22 | * Extended [[org.springframework.beans.factory.config.BeanDefinition]] 23 | * interface that exposes a bean creation function. 24 | * 25 | * @author Arjen Poutsma 26 | * @see FunctionalGenericBeanDefinition 27 | */ 28 | trait FunctionalBeanDefinition[T] extends BeanDefinition { 29 | 30 | /** 31 | * Returns the bean creation function. 32 | * @return the bean creation function 33 | */ 34 | def beanCreationFunction: () => T 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/beans/factory/function/FunctionalRootBeanDefinition.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory.function 18 | 19 | import org.springframework.beans.factory.support.RootBeanDefinition 20 | 21 | /** 22 | * Default implementation of 23 | * [[org.springframework.scala.beans.factory.function.FunctionalBeanDefinition]]. 24 | * 25 | * @author Arjen Poutsma 26 | */ 27 | class FunctionalRootBeanDefinition[T](beanFunction: () => T, targetType: Class[T]) 28 | extends RootBeanDefinition with FunctionalBeanDefinition[T] { 29 | 30 | setBeanClass(classOf[Function0Wrapper]) 31 | getConstructorArgumentValues.addIndexedArgumentValue(0, beanFunction) 32 | setFactoryMethodName("apply") 33 | setTargetType(targetType) 34 | 35 | 36 | def beanCreationFunction = beanFunction 37 | } 38 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/beans/factory/function/InitDestroyFunctionBeanPostProcessor.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory.function 18 | 19 | import scala.beans.BeanProperty 20 | import scala.collection.mutable 21 | import scala.collection.mutable.ListBuffer 22 | 23 | import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor 24 | import org.springframework.core.PriorityOrdered 25 | import org.springframework.util.{Assert, StringUtils} 26 | 27 | /** 28 | * [[org.springframework.beans.factory.config.BeanPostProcessor]] implementation 29 | * that invokes init and destroy functions. Allows for an functional 30 | * alternative to Spring's [[org.springframework.beans.factory.InitializingBean]] 31 | * and [[org.springframework.beans.factory.DisposableBean]] callback interfaces. 32 | * 33 | * Initialization functions are defined as `(T) => Unit`, i.e. a function that takes the 34 | * bean as parameter, but does not return anything. 35 | * 36 | * Destruction functions are defined as `(T) => Unit`, i.e. a function that takes the bean 37 | * as parameter, but does not return anything. 38 | * 39 | * @author Arjen Poutsma 40 | */ 41 | class InitDestroyFunctionBeanPostProcessor 42 | extends DestructionAwareBeanPostProcessor with PriorityOrdered { 43 | 44 | val initFunctions = new mutable.HashMap[String, ListBuffer[Function1[Any, Unit]]] 45 | 46 | val destroyFunctions = new mutable.HashMap[String, ListBuffer[Function1[Any, Unit]]] 47 | 48 | @BeanProperty 49 | var order: Int = org.springframework.core.Ordered.LOWEST_PRECEDENCE 50 | 51 | /** 52 | * Registers an initialization function for the bean with the given name. 53 | * 54 | * Initialization functions are defined as `(T) => Unit`, i.e. a function that takes the 55 | * bean as parameter, but does not return anything. 56 | * 57 | * @param beanName the name of the bean to register the initialization function for 58 | * @param initFunction the initialization function 59 | * @tparam T the bean type 60 | */ 61 | def registerInitFunction[T](beanName: String, initFunction: (T) => Unit) { 62 | assert(StringUtils.hasLength(beanName), "'beanName' must not be empty") 63 | assert(initFunction != null, "'initFunction' must not be null") 64 | 65 | addFunction(initFunctions, beanName, initFunction.asInstanceOf[Function1[Any, Unit]]) 66 | } 67 | 68 | /** 69 | * Registers a destruction function for the bean with the given name. 70 | * 71 | * Destruction functions are defined as `(T) => Unit`, i.e. a function that takes the 72 | * bean as parameter, but does not return anything. 73 | * 74 | * @param beanName the name of the bean to register the destruction function for 75 | * @param destroyFunction the destruction function 76 | * @tparam T the bean type 77 | */ 78 | def registerDestroyFunction[T](beanName: String, destroyFunction: (T) => Unit) { 79 | Assert.hasLength(beanName, "'beanName' must not be empty") 80 | Assert.notNull(destroyFunction, "'destroyFunction' must not be null") 81 | 82 | addFunction(destroyFunctions, beanName, destroyFunction.asInstanceOf[Function1[Any, Unit]]) 83 | } 84 | 85 | private def addFunction(functionsMap: mutable.HashMap[String, ListBuffer[Function1[Any, Unit]]], 86 | beanName: String, 87 | function: (Any) => Unit) { 88 | 89 | functionsMap.get(beanName) match { 90 | case None => 91 | val list = new ListBuffer[Function1[Any, Unit]] 92 | list += function 93 | functionsMap(beanName) = list 94 | case Some(list) => 95 | list += function 96 | } 97 | } 98 | 99 | def postProcessBeforeInitialization(bean: AnyRef, beanName: String): AnyRef = { 100 | initFunctions.get(beanName).foreach(_.foreach(_.apply(bean))) 101 | bean 102 | } 103 | 104 | def postProcessAfterInitialization(bean: AnyRef, beanName: String) = bean 105 | 106 | def postProcessBeforeDestruction(bean: AnyRef, beanName: String) { 107 | destroyFunctions.get(beanName).foreach(_.foreach(_.apply(bean))) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/beans/factory/xml/UtilNamespaceHandler.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory.xml 18 | 19 | import org.springframework.util.StringUtils 20 | import org.w3c.dom.Element 21 | import org.springframework.beans.factory.xml.{ParserContext, AbstractSingleBeanDefinitionParser, NamespaceHandlerSupport} 22 | import org.springframework.beans.factory.support.BeanDefinitionBuilder 23 | import org.springframework.scala.beans.factory.config.{MapFactoryBean, SetFactoryBean, SeqFactoryBean} 24 | 25 | /** 26 | * Namespace handler for the `scala-util` namespace. 27 | * 28 | * @author Arjen Poutsma 29 | */ 30 | class UtilNamespaceHandler extends NamespaceHandlerSupport { 31 | 32 | private final val SCOPE_ATTRIBUTE: String = "scope" 33 | 34 | def init() { 35 | registerBeanDefinitionParser("seq", new SeqBeanDefinitionParser()) 36 | registerBeanDefinitionParser("set", new SetBeanDefinitionParser()) 37 | registerBeanDefinitionParser("map", new MapBeanDefinitionParser()) 38 | } 39 | 40 | private def parseScope(element: Element, builder: BeanDefinitionBuilder) { 41 | val scope: String = element.getAttribute(SCOPE_ATTRIBUTE) 42 | if (StringUtils.hasLength(scope)) { 43 | builder.setScope(scope) 44 | } 45 | } 46 | 47 | class SeqBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 48 | 49 | protected override def getBeanClass(element: Element) = classOf[SeqFactoryBean[_]] 50 | 51 | protected override def doParse(element: Element, 52 | parserContext: ParserContext, 53 | builder: BeanDefinitionBuilder) { 54 | val parsedList: java.util.List[_] = parserContext.getDelegate 55 | .parseListElement(element, builder.getRawBeanDefinition) 56 | builder.addConstructorArgValue(parsedList) 57 | /* 58 | // val listClass: String = element.getAttribute("list-class") 59 | if (StringUtils.hasText(listClass)) { 60 | builder.addPropertyValue("targetListClass", listClass) 61 | } 62 | */ 63 | parseScope(element, builder) 64 | } 65 | } 66 | 67 | private class SetBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 68 | 69 | protected override def getBeanClass(element: Element): Class[_] = classOf[SetFactoryBean[_]] 70 | 71 | protected override def doParse(element: Element, 72 | parserContext: ParserContext, 73 | builder: BeanDefinitionBuilder) { 74 | val parsedSet: java.util.Set[_] = parserContext.getDelegate 75 | .parseSetElement(element, builder.getRawBeanDefinition) 76 | builder.addConstructorArgValue(parsedSet) 77 | /* 78 | val setClass: String = element.getAttribute("set-class") 79 | if (StringUtils.hasText(setClass)) { 80 | builder.addPropertyValue("targetSetClass", setClass) 81 | } 82 | */ 83 | parseScope(element, builder) 84 | } 85 | } 86 | 87 | private class MapBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 88 | 89 | protected override def getBeanClass(element: Element): Class[_] = classOf[MapFactoryBean[_, _]] 90 | 91 | protected override def doParse(element: Element, 92 | parserContext: ParserContext, 93 | builder: BeanDefinitionBuilder) { 94 | val parsedMap: java.util.Map[_, _] = parserContext.getDelegate 95 | .parseMapElement(element, builder.getRawBeanDefinition) 96 | builder.addConstructorArgValue(parsedMap) 97 | /* 98 | val mapClass: String = element.getAttribute("map-class") 99 | if (StringUtils.hasText(mapClass)) { 100 | builder.addPropertyValue("targetMapClass", mapClass) 101 | } 102 | */ 103 | parseScope(element, builder) 104 | } 105 | } 106 | 107 | } -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/beans/propertyeditors/RegexEditor.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.propertyeditors 18 | 19 | import java.beans.PropertyEditorSupport 20 | import util.matching.Regex 21 | 22 | /** 23 | * Editor for [[scala.util.matching.Regex]], to directly populate a `Regex` property. 24 | * Expects the same syntax as the Regex constructor, or 25 | * [[java.util.regex.Pattern.compile]]. 26 | * 27 | * @author Arjen Poutsma 28 | */ 29 | class RegexEditor extends PropertyEditorSupport { 30 | 31 | override def setAsText(text: String) { 32 | text match { 33 | case null => setValue(null) 34 | case s => setValue(s.r) 35 | } 36 | } 37 | 38 | override def getAsText: String = { 39 | getValue match { 40 | case null => "" 41 | case regex: Regex => regex.pattern.pattern() 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/beans/propertyeditors/ScalaCollectionEditor.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.propertyeditors 18 | 19 | import java.beans.PropertyEditorSupport 20 | import scala.collection.JavaConversions._ 21 | import scala.collection.mutable 22 | 23 | /** 24 | * Property editor for Scala collections, converting any source collection to a given 25 | * target collection type. 26 | * 27 | * @author Arjen Poutsma 28 | * @tparam T the type of elements in the collection 29 | * @param builderFunction function that creates a [[scala.collection.mutable.Builder]] 30 | * @param nullAsEmptyCollection whether to convert an incoming `null` value to an empty 31 | * collection (of the appropriate type). Defaults to `false`. 32 | */ 33 | class ScalaCollectionEditor[T, U](val builderFunction: () => mutable.Builder[T, _], 34 | val nullAsEmptyCollection: Boolean = false) 35 | extends PropertyEditorSupport { 36 | 37 | override def setAsText(text: String) { 38 | setValue(text) 39 | } 40 | 41 | override def setValue(value: AnyRef) { 42 | val builder = builderFunction() 43 | value match { 44 | case null if !nullAsEmptyCollection => { 45 | super.setValue(null) 46 | return 47 | } 48 | case null if nullAsEmptyCollection => { 49 | builder.clear() 50 | } 51 | case source: TraversableOnce[T] => { 52 | builder ++= source 53 | } 54 | case javaCollection: java.util.Collection[T] => { 55 | builder ++= collectionAsScalaIterable(javaCollection) 56 | } 57 | case javaMap: java.util.Map[T, U] => { 58 | val mapBuilder = builder.asInstanceOf[mutable.Builder[(T, U), _]] 59 | mapBuilder ++= mapAsScalaMap(javaMap) 60 | } 61 | case el=> { 62 | builder += el.asInstanceOf[T] 63 | } 64 | } 65 | super.setValue(builder.result()) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/beans/propertyeditors/ScalaEditorRegistrar.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.propertyeditors 18 | 19 | import scala.util.matching.Regex 20 | 21 | import org.springframework.beans.{PropertyEditorRegistry, PropertyEditorRegistrar} 22 | 23 | /** 24 | * Property editor registrar for Scala property editors. 25 | * 26 | * @author Arjen Poutsma 27 | */ 28 | class ScalaEditorRegistrar extends PropertyEditorRegistrar { 29 | 30 | def registerCustomEditors(registry: PropertyEditorRegistry) { 31 | // Types 32 | registry.registerCustomEditor(classOf[Regex], new RegexEditor()) 33 | 34 | // Seq 35 | registry.registerCustomEditor(classOf[scala.collection.Seq[Any]], new ScalaCollectionEditor(scala.collection.Seq.newBuilder[Any] _)) 36 | registry.registerCustomEditor(classOf[scala.collection.immutable.Seq[Any]], new ScalaCollectionEditor(scala.collection.immutable.Seq.newBuilder[Any] _)) 37 | registry.registerCustomEditor(classOf[scala.collection.mutable.Seq[Any]], new ScalaCollectionEditor(scala.collection.mutable.Seq.newBuilder[Any] _)) 38 | 39 | // IndexedSeq 40 | registry.registerCustomEditor(classOf[scala.collection.IndexedSeq[Any]], new ScalaCollectionEditor(scala.collection.IndexedSeq.newBuilder[Any] _)) 41 | registry.registerCustomEditor(classOf[scala.collection.immutable.IndexedSeq[Any]], new ScalaCollectionEditor(scala.collection.immutable.IndexedSeq.newBuilder[Any] _)) 42 | registry.registerCustomEditor(classOf[scala.collection.mutable.IndexedSeq[Any]], new ScalaCollectionEditor(scala.collection.mutable.IndexedSeq.newBuilder[Any] _)) 43 | 44 | // ResizableArray 45 | registry.registerCustomEditor(classOf[scala.collection.mutable.ResizableArray[Any]], new ScalaCollectionEditor(scala.collection.mutable.ResizableArray.newBuilder[Any] _)) 46 | 47 | // LinearSeq 48 | registry.registerCustomEditor(classOf[scala.collection.LinearSeq[Any]], new ScalaCollectionEditor(scala.collection.LinearSeq.newBuilder[Any] _)) 49 | registry.registerCustomEditor(classOf[scala.collection.immutable.LinearSeq[Any]], new ScalaCollectionEditor(scala.collection.immutable.LinearSeq.newBuilder[Any] _)) 50 | registry.registerCustomEditor(classOf[scala.collection.mutable.LinearSeq[Any]], new ScalaCollectionEditor(scala.collection.mutable.LinearSeq.newBuilder[Any] _)) 51 | 52 | // Buffer 53 | registry.registerCustomEditor(classOf[scala.collection.mutable.Buffer[Any]], new ScalaCollectionEditor(scala.collection.mutable.Buffer.newBuilder[Any] _)) 54 | 55 | // Set 56 | registry.registerCustomEditor(classOf[scala.collection.Set[Any]], new ScalaCollectionEditor(scala.collection.Set.newBuilder[Any] _)) 57 | registry.registerCustomEditor(classOf[scala.collection.immutable.Set[Any]], new ScalaCollectionEditor(scala.collection.immutable.Set.newBuilder[Any] _)) 58 | registry.registerCustomEditor(classOf[scala.collection.mutable.Set[Any]], new ScalaCollectionEditor(scala.collection.mutable.Set.newBuilder[Any] _)) 59 | 60 | /* 61 | TODO: make SortedSets work 62 | // SortedSet 63 | registry.registerCustomEditor(classOf[scala.collection.SortedSet[Any]], new ScalaCollectionEditor(scala.collection.SortedSet.newBuilder[String] _)) 64 | registry.registerCustomEditor(classOf[scala.collection.immutable.SortedSet[Any]], new ScalaCollectionEditor(scala.collection.immutable.SortedSet.newBuilder[String] _)) 65 | */ 66 | 67 | // Map 68 | registry.registerCustomEditor(classOf[scala.collection.Map[Any, Any]], new ScalaCollectionEditor(scala.collection.Map.newBuilder[Any, Any] _)) 69 | registry.registerCustomEditor(classOf[scala.collection.immutable.Map[Any, Any]], new ScalaCollectionEditor(scala.collection.immutable.Map.newBuilder[Any, Any] _)) 70 | registry.registerCustomEditor(classOf[scala.collection.mutable.Map[Any, Any]], new ScalaCollectionEditor(scala.collection.mutable.Map.newBuilder[Any, Any] _)) 71 | 72 | 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/context/ApplicationContextConversions.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.context 18 | 19 | import org.springframework.context.ApplicationContext 20 | import org.springframework.scala.beans.factory.RichListableBeanFactory 21 | import org.springframework.scala.beans.factory.BeanFactoryConversions._ 22 | import scala.reflect.ClassTag 23 | 24 | /** 25 | * A collection of implicit conversions between application contexts and their rich 26 | * counterpart. 27 | * 28 | * @author Arjen Poutsma 29 | */ 30 | object ApplicationContextConversions { 31 | 32 | /** 33 | * Implicitly converts a [[org.springframework.context.ApplicationContext]] to a 34 | * [[org.springframework.scala.context.RichApplicationContext]]. 35 | * 36 | * @param appContext the application context to be converted 37 | * @return the rich application context 38 | */ 39 | implicit def toRichApplicationContext(appContext: ApplicationContext): RichApplicationContext = 40 | new DefaultRichApplicationContext(appContext) 41 | 42 | } 43 | 44 | private[springframework] class DefaultRichApplicationContext(val appContext: ApplicationContext) 45 | extends RichApplicationContext { 46 | 47 | private val beanFactory: RichListableBeanFactory = appContext 48 | 49 | def apply[T : ClassTag]() = beanFactory.apply[T]() 50 | 51 | def apply[T : ClassTag](name: String) = beanFactory.apply[T](name) 52 | 53 | def beanNamesForType[T : ClassTag](includeNonSingletons: Boolean, allowEagerInit: Boolean) = 54 | beanFactory.beanNamesForType[T](includeNonSingletons, allowEagerInit) 55 | 56 | def beansOfType[T : ClassTag](includeNonSingletons: Boolean, allowEagerInit: Boolean) = 57 | beanFactory.beansOfType[T](includeNonSingletons, allowEagerInit) 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/context/ApplicationListenerAdapter.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.context 18 | 19 | import org.springframework.context.{ApplicationListener, ApplicationEvent} 20 | 21 | /** 22 | * Adapter to allow handling [[org.springframework.context.ApplicationEvent]]s with 23 | * pattern matching. 24 | * 25 | * @author Tomasz Nurkiewicz 26 | * @author Arjen Poutsma 27 | */ 28 | trait ApplicationListenerAdapter extends ApplicationListener[ApplicationEvent] { 29 | 30 | final def onApplicationEvent(event: ApplicationEvent) { 31 | if (onEvent isDefinedAt event) { 32 | onEvent(event) 33 | } 34 | } 35 | 36 | /** 37 | * Handle an application event with a function. 38 | * 39 | * @return a function that takes an [[org.springframework.context.ApplicationEvent]] as 40 | * parameter 41 | */ 42 | def onEvent: PartialFunction[ApplicationEvent, Unit] 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/context/RichApplicationContext.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.context 18 | 19 | import org.springframework.scala.beans.factory.RichListableBeanFactory 20 | 21 | /** 22 | * @author Arjen Poutsma 23 | */ 24 | trait RichApplicationContext extends RichListableBeanFactory { 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/context/function/BeanLookupFunction.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.context.function 18 | 19 | /** 20 | * Function that looks up a bean in a bean factory. Also allows 21 | * for registration of init and destroy methods. 22 | * 23 | * @author Arjen Poutsma 24 | * @see FunctionalConfiguration 25 | */ 26 | trait BeanLookupFunction[T] extends Function0[T] { 27 | 28 | /** 29 | * Registers an initialization function. 30 | * 31 | * @param initFunction the initialization function 32 | */ 33 | def init(initFunction: T => Unit): BeanLookupFunction[T] 34 | 35 | /** 36 | * Registers a destruction function. 37 | * 38 | * @param destroyFunction the destruction function 39 | */ 40 | def destroy(destroyFunction: T => Unit): BeanLookupFunction[T] 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/context/function/ContextSupport.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.context.function 18 | 19 | import org.springframework.context.support.GenericApplicationContext 20 | import org.springframework.beans.factory.support.BeanNameGenerator 21 | import org.springframework.context.annotation.{ScopedProxyMode, ScopeMetadataResolver, ClassPathBeanDefinitionScanner, AnnotationConfigUtils} 22 | import org.springframework.core.`type`.filter.TypeFilter 23 | 24 | /** 25 | * Defines the configuration elements for the Spring Framework's application context 26 | * support. Effects the activation of various configuration styles for the containing 27 | * Spring ApplicationContext. 28 | * 29 | * @author Arjen Poutsma 30 | * @author Henryk Konsek 31 | */ 32 | trait ContextSupport { 33 | self: FunctionalConfiguration => 34 | 35 | /** 36 | * Activates various annotations to be detected in bean classes: Spring's 37 | * [[org.springframework.beans.factory.annotation.Required]] and 38 | * [[org.springframework.beans.factory.annotation.Autowired]], as well as JSR 250's 39 | * [[javax.annotation.PostConstruct]], [[javax.annotation.PreDestroy]] and 40 | * [[javax.annotation.Resource]] (if available), 41 | * JAX-WS's [[javax.xml.ws.WebServiceRef]] (if available), 42 | * EJB3's `EJB` (if available), 43 | * and JPA's `PersistenceContext` and `PersistenceUnit` (if available). 44 | * Alternatively, you may choose to activate the individual BeanPostProcessors for 45 | * those annotations. 46 | * 47 | * @note This method does not activate processing of Spring's 48 | * [[org.springframework.transaction.annotation.Transactional]] or 49 | * EJB3's `TransactionAttribute` annotation. Consider the use of the `TransactionSupport` 50 | * configuration trait for that purpose. 51 | */ 52 | def enableAnnotationConfig() { 53 | onRegister((applicationContext: GenericApplicationContext, 54 | beanNameGenerator: BeanNameGenerator) => { 55 | AnnotationConfigUtils.registerAnnotationConfigProcessors(applicationContext) 56 | }) 57 | } 58 | 59 | /** 60 | * Scans the classpath for annotated components that will be auto-registered as 61 | * Spring beans. By default, the Spring-provided 62 | * [[org.springframework.stereotype.Component]], 63 | * [[org.springframework.stereotype.Repository]], 64 | * [[org.springframework.stereotype.Service]], and 65 | * [[org.springframework.stereotype.Controller]] stereotypes will be detected. 66 | * 67 | * This method is an equivalent of the `context:component-scan` element of the Spring 68 | * Schema configuration. 69 | * 70 | * @param basePackages the packages to check for annotated classes 71 | * @param useDefaultFilters useDefaultFilters whether to include the default filters for 72 | * the [[org.springframework.stereotype.Component]], 73 | * [[org.springframework.stereotype.Repository]], 74 | * [[org.springframework.stereotype.Service]], and 75 | * [[org.springframework.stereotype.Controller]] stereotype 76 | * @param resourcePattern the resource pattern to use when scanning the classpath. This 77 | * value will be appended to each base package name. 78 | * @param beanNameGenerator the [[org.springframework.beans.factory.support.BeanNameGenerator]] 79 | * to use for detected bean classes. Default name generator is 80 | * inherited from the [[org.springframework.scala.context.function.FunctionalConfiguration]]. 81 | * @param scopeResolver the [[org.springframework.context.annotation.ScopeMetadataResolver]] to use for detected 82 | * bean classes. Note that this will override any custom `scopedProxyMode` setting. The default 83 | * is an [[org.springframework.context.annotation.AnnotationScopeMetadataResolver]]. 84 | * @param scopedProxy the proxy behavior for non-singleton scoped beans. Note that this will override any custom 85 | * `scopeMetadataResolver` setting. The default is `ScopedProxyMode#NO`. 86 | * @param includeFilters include filters to the resulting classes to find candidates 87 | * @param excludeFilters exclude filters to the resulting classes to find candidates 88 | */ 89 | def componentScan(basePackages: Seq[String], 90 | useDefaultFilters: Boolean = true, 91 | resourcePattern: Option[String] = None, 92 | beanNameGenerator: Option[BeanNameGenerator] = None, 93 | scopeResolver: Option[ScopeMetadataResolver] = None, 94 | scopedProxy: Option[ScopedProxyMode] = None, 95 | includeFilters: Seq[TypeFilter] = Seq.empty, 96 | excludeFilters: Seq[TypeFilter] = Seq.empty) { 97 | if (scopeResolver.isDefined && scopedProxy.isDefined) { 98 | throw new IllegalArgumentException( 99 | "Cannot define both 'scopeResolver' and 'scopedProxy' on 'componentScan' option") 100 | } 101 | 102 | onRegister((applicationContext: GenericApplicationContext, 103 | defaultBeanNameGenerator: BeanNameGenerator) => { 104 | val scanner = new ClassPathBeanDefinitionScanner(beanRegistry, useDefaultFilters) 105 | scanner.setResourceLoader(applicationContext) 106 | scanner.setEnvironment(environment) 107 | includeFilters.foreach(scanner.addIncludeFilter(_)) 108 | excludeFilters.foreach(scanner.addExcludeFilter(_)) 109 | resourcePattern.foreach(scanner.setResourcePattern(_)) 110 | scanner.setBeanNameGenerator(beanNameGenerator.getOrElse(defaultBeanNameGenerator)) 111 | scopeResolver.foreach(scanner.setScopeMetadataResolver(_)) 112 | scopedProxy.foreach(scanner.setScopedProxyMode(_)) 113 | scanner.scan(basePackages: _*) 114 | }) 115 | } 116 | 117 | /** 118 | * Convenience method used to invoke component scanning with default parameters and 119 | * varargs list of the base packages. 120 | * 121 | * @param basePackages the packages to check for annotated classes 122 | */ 123 | def componentScan(basePackages: String*) { 124 | componentScan(basePackages = basePackages) 125 | } 126 | 127 | } -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/context/function/FunctionalConfigApplicationContext.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.context.function 18 | 19 | import org.springframework.context.support.GenericApplicationContext 20 | import org.springframework.util.CollectionUtils 21 | import scala.collection.JavaConversions._ 22 | import org.springframework.beans.BeanUtils 23 | import org.springframework.beans.factory.support.{DefaultBeanNameGenerator, BeanNameGenerator} 24 | import org.springframework.scala.context.RichApplicationContext 25 | import org.springframework.scala.util.TypeTagUtils.typeToClass 26 | import scala.reflect.ClassTag 27 | 28 | /** 29 | * Standalone application context, accepting 30 | * [[org.springframework.scala.context.function.FunctionalConfiguration]] 31 | * classes as input. Allows for registering classes one by one using 32 | * ``registerClasses`` as well as registering functional configuration 33 | * instances with ``registerConfigurations``. 34 | * 35 | * In case of multiple ``FunctionalConfiguration`` classes, beans defined in 36 | * later configurations will override those defined in earlier configurations. 37 | * This can be leveraged to deliberately override certain bean definitions via 38 | * an extra configuration. 39 | * 40 | * @author Arjen Poutsma 41 | * @see FunctionalConfiguration 42 | */ 43 | class FunctionalConfigApplicationContext 44 | extends GenericApplicationContext with RichApplicationContext { 45 | 46 | var beanNameGenerator: BeanNameGenerator = new DefaultBeanNameGenerator 47 | 48 | private val richApplicationContext: RichApplicationContext = this 49 | 50 | /** 51 | * Registers a single [[org.springframework.scala.context.function.FunctionalConfiguration]] 52 | * classes to be processed. Note that ``refresh()`` must be called in order for 53 | * the context to fully process the given configurations. 54 | * @tparam T the configuration class 55 | */ 56 | def registerClass[T <: FunctionalConfiguration : ClassTag]() { 57 | registerClasses(typeToClass[T]) 58 | } 59 | 60 | /** 61 | * Registers one or more [[org.springframework.scala.context.function.FunctionalConfiguration]] 62 | * classes to be processed. Note that ``refresh()`` must be called in order for 63 | * the context to fully process the given configurations. 64 | * @param configurationClasses one or more functional configuration classes 65 | */ 66 | def registerClasses(configurationClasses: Class[_ <: FunctionalConfiguration]*) { 67 | require(!CollectionUtils.isEmpty(configurationClasses), 68 | "At least one functional configuration class must be specified") 69 | val configurations = configurationClasses.map(BeanUtils.instantiate(_)) 70 | registerConfigurations(configurations: _*) 71 | } 72 | 73 | /** 74 | * Registers one or more [[org.springframework.scala.context.function.FunctionalConfiguration]]s 75 | * to be processed. Note that ``refresh()`` must be called in order for 76 | * the context to fully process the given configurations. 77 | * @param configurations one or more functional configurations 78 | */ 79 | def registerConfigurations(configurations: FunctionalConfiguration*) { 80 | require(!CollectionUtils.isEmpty(configurations), 81 | "At least one configuration must be specified") 82 | configurations.foreach(_.register(this, beanNameGenerator)) 83 | } 84 | 85 | def apply[T: ClassTag]() = { 86 | getBean(typeToClass[T]) 87 | } 88 | 89 | def apply[T: ClassTag](name: String) = 90 | getBean(name, typeToClass[T]) 91 | 92 | def beanNamesForType[T: ClassTag](includeNonSingletons: Boolean, allowEagerInit: Boolean) = 93 | getBeanNamesForType(typeToClass[T], includeNonSingletons, allowEagerInit) 94 | 95 | def beansOfType[T: ClassTag](includeNonSingletons: Boolean, allowEagerInit: Boolean) = 96 | getBeansOfType(typeToClass[T], includeNonSingletons, allowEagerInit).toMap 97 | } 98 | 99 | /** 100 | * Companion object to the ``FunctionalConfigApplicationContext`` class. 101 | * 102 | * @author Arjen Poutsma 103 | */ 104 | object FunctionalConfigApplicationContext { 105 | 106 | /** 107 | * Creates a new ``FunctionalConfigApplicationContext``, deriving bean 108 | * definitions from the given configuration type parameter and automatically 109 | * refreshing the context. 110 | * @tparam T the configuration class 111 | */ 112 | def apply[T <: FunctionalConfiguration : ClassTag](): FunctionalConfigApplicationContext = { 113 | val context = new FunctionalConfigApplicationContext() 114 | context.registerClass[T]() 115 | context.refresh() 116 | context 117 | } 118 | 119 | /** 120 | * Creates a new ``FunctionalConfigApplicationContext``, deriving bean 121 | * definitions from the given configuration classes and automatically 122 | * refreshing the context. 123 | * @param configurationClasses one or more functional configuration classes 124 | */ 125 | def apply(configurationClasses: Class[_ <: FunctionalConfiguration]*): FunctionalConfigApplicationContext = { 126 | val context = new FunctionalConfigApplicationContext() 127 | context.registerClasses(configurationClasses: _*) 128 | context.refresh() 129 | context 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/http/converter/xml/ElemMessageConverter.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.http.converter.xml 18 | 19 | import org.springframework.http.converter.AbstractHttpMessageConverter 20 | import org.springframework.http.{MediaType, HttpInputMessage, HttpOutputMessage} 21 | import scala.xml.{XML, Elem} 22 | import java.nio.charset.Charset 23 | import java.io.OutputStreamWriter 24 | 25 | /** 26 | * @author Arjen Poutsma 27 | */ 28 | class ElemMessageConverter extends AbstractHttpMessageConverter[Elem](MediaType.APPLICATION_XML, MediaType.TEXT_XML, 29 | new MediaType("application", "*+xml")) { 30 | 31 | final val DEFAULT_CHARSET: Charset = Charset.forName("UTF-8") 32 | 33 | def supports(clazz: Class[_]) = { 34 | classOf[Elem] == clazz 35 | } 36 | 37 | def readInternal(clazz: Class[_ <: Elem], inputMessage: HttpInputMessage): Elem = { 38 | XML.load(inputMessage.getBody) 39 | } 40 | 41 | def writeInternal(t: Elem, outputMessage: HttpOutputMessage) { 42 | val contentType = getContentType(outputMessage) 43 | val writer = new OutputStreamWriter(outputMessage.getBody, contentType) 44 | 45 | XML.write(writer, t, contentType.toString, false, null) 46 | } 47 | 48 | private def getContentType(outputMessage: HttpOutputMessage) = { 49 | val contentType: MediaType = outputMessage.getHeaders.getContentType 50 | if (contentType != null && contentType.getCharSet != null) { 51 | contentType.getCharSet 52 | } 53 | DEFAULT_CHARSET 54 | } 55 | } -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/jdbc/core/JdbcCallbackConversions.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.jdbc.core 18 | 19 | import java.sql.{CallableStatement, PreparedStatement, Connection, ResultSet} 20 | import org.springframework.jdbc.core._ 21 | 22 | /** 23 | * A collection of implicit conversions between 24 | * [[org.springframework.jdbc.core.JdbcTemplate]] callback interfaces and functions. 25 | * 26 | * @author Henryk Konsek 27 | */ 28 | object JdbcCallbackConversions { 29 | 30 | // Prepared Statement conversions 31 | /** 32 | * Implicitly converts a function to a 33 | * [[org.springframework.jdbc.core.PreparedStatementCreator]]. 34 | * 35 | * @param statementCreator the function 36 | * @return the `PreparedStatementCreator` 37 | */ 38 | implicit def asPreparedStatementCreator(statementCreator: Connection => PreparedStatement): PreparedStatementCreator = { 39 | new PreparedStatementCreator { 40 | def createPreparedStatement(connection: Connection): PreparedStatement = statementCreator( 41 | connection) 42 | } 43 | } 44 | 45 | /** 46 | * Implicitly converts a function to a 47 | * [[org.springframework.jdbc.core.PreparedStatementCallback]]. 48 | * 49 | * @param statementCallback the function 50 | * @return the `PreparedStatementCallback` 51 | */ 52 | implicit def asPreparedStatementCallback[T](statementCallback: PreparedStatement => T): PreparedStatementCallback[T] = { 53 | new PreparedStatementCallback[T] { 54 | def doInPreparedStatement(statement: PreparedStatement): T = statementCallback( 55 | statement) 56 | } 57 | } 58 | 59 | /** 60 | * Implicitly converts a function to a 61 | * [[org.springframework.jdbc.core.PreparedStatementSetter]]. 62 | * 63 | * @param setterCallback the function 64 | * @return the `PreparedStatementSetter` 65 | */ 66 | implicit def asPreparedStatementSetter(setterCallback: PreparedStatement => Unit): PreparedStatementSetter = { 67 | new PreparedStatementSetter() { 68 | def setValues(statement: PreparedStatement) { 69 | setterCallback(statement) 70 | } 71 | } 72 | } 73 | 74 | // Callable Statement conversions 75 | /** 76 | * Implicitly converts a function to a 77 | * [[org.springframework.jdbc.core.CallableStatementCreator]]. 78 | * 79 | * @param statementCreator the function 80 | * @return the `CallableStatementCreator` 81 | */ 82 | implicit def asCallableStatementCreator(statementCreator: Connection => CallableStatement): CallableStatementCreator = { 83 | new CallableStatementCreator() { 84 | def createCallableStatement(connection: Connection): CallableStatement = statementCreator( 85 | connection) 86 | } 87 | } 88 | 89 | /** 90 | * Implicitly converts a function to a 91 | * [[org.springframework.jdbc.core.PreparedStatementCallback]]. 92 | * 93 | * @param statementCallback the function 94 | * @return the `CallableStatementCallback` 95 | */ 96 | implicit def asCallableStatementCallback[T](statementCallback: CallableStatement => T): CallableStatementCallback[T] = { 97 | new CallableStatementCallback[T] { 98 | def doInCallableStatement(statement: CallableStatement): T = statementCallback( 99 | statement) 100 | } 101 | } 102 | 103 | // Result Set conversions 104 | /** 105 | * Implicitly converts a function to a 106 | * [[org.springframework.jdbc.core.RowMapper]]. 107 | * 108 | * @param mapper the function 109 | * @return the `RowMapper` 110 | */ 111 | implicit def asRowMapper[T](mapper: (ResultSet, Int) => T): RowMapper[T] = { 112 | new RowMapper[T] { 113 | def mapRow(resultSet: ResultSet, rowNum: Int) = mapper(resultSet, rowNum) 114 | } 115 | } 116 | 117 | /** 118 | * Implicitly converts a function to a 119 | * [[org.springframework.jdbc.core.ResultSetExtractor]]. 120 | * 121 | * @param extractor the function 122 | * @return the `ResultSetExtractor` 123 | */ 124 | implicit def asResultSetExtractor[T](extractor: ResultSet => T): ResultSetExtractor[T] = { 125 | new ResultSetExtractor[T]() { 126 | def extractData(resultSet: ResultSet): T = extractor(resultSet) 127 | } 128 | } 129 | 130 | /** 131 | * Implicitly converts a function to a 132 | * [[org.springframework.jdbc.core.RowCallbackHandler]]. 133 | * 134 | * @param rowProcessor the function 135 | * @return the `RowCallbackHandler` 136 | */ 137 | implicit def asRowCallbackHandler(rowProcessor: ResultSet => Unit): RowCallbackHandler = { 138 | new RowCallbackHandler() { 139 | def processRow(rs: ResultSet) { 140 | rowProcessor(rs) 141 | } 142 | } 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/test/context/FunctionalConfigContextLoader.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.test.context 18 | 19 | import org.springframework.context.ApplicationContext 20 | import org.springframework.context.annotation.AnnotationConfigUtils.registerAnnotationConfigProcessors 21 | import org.springframework.scala.context.function.{FunctionalConfiguration, FunctionalConfigApplicationContext} 22 | import org.springframework.test.context.{ContextConfigurationAttributes, MergedContextConfiguration} 23 | import org.springframework.test.context.support.AbstractContextLoader 24 | 25 | import scala.UnsupportedOperationException 26 | 27 | /** 28 | * Implementation of [[org.springframework.test.context.SmartContextLoader]] supporting 29 | * [[org.springframework.scala.context.function.FunctionalConfiguration]]. 30 | * 31 | * @note Note that [[org.springframework.scala.context.function.FunctionalConfigApplicationContext]]s 32 | * loaded by this class have annotation config support enabled. 33 | * 34 | * @author Henryk Konsek 35 | */ 36 | class FunctionalConfigContextLoader extends AbstractContextLoader { 37 | 38 | private var configClasses: Seq[Class[_ <: FunctionalConfiguration]] = _ 39 | 40 | override def processContextConfiguration(configAttributes: ContextConfigurationAttributes) { 41 | configClasses = FunctionalConfigurations.resolveConfigurationsFromTestClass(configAttributes.getDeclaringClass) 42 | } 43 | 44 | override def loadContext(mergedConfig: MergedContextConfiguration): ApplicationContext = { 45 | val context = new FunctionalConfigApplicationContext() 46 | prepareContext(context, mergedConfig) 47 | context.registerClasses(configClasses: _*) 48 | registerAnnotationConfigProcessors(context) 49 | context.refresh() 50 | context 51 | } 52 | 53 | override def loadContext(locations: String*): ApplicationContext = { 54 | throw new UnsupportedOperationException("FunctionalConfigContextLoader supports only SmartContextLoader API.") 55 | } 56 | 57 | override def getResourceSuffix: String = { 58 | throw new UnsupportedOperationException("FunctionalConfigContextLoader does not support the getResourceSuffix() method") 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/test/context/FunctionalConfigurations.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.test.context 18 | 19 | import org.springframework.scala.context.function.FunctionalConfiguration 20 | import org.springframework.util.ClassUtils.{getDefaultClassLoader => defaultClassLoader} 21 | import scala.annotation.StaticAnnotation 22 | import scala.reflect.runtime.universe.typeOf 23 | import scala.reflect.runtime.universe.Constant 24 | import scala.reflect.runtime.universe.termNames 25 | import scala.reflect.runtime.universe.runtimeMirror 26 | import scala.reflect.runtime.universe.TypeRef 27 | 28 | /** 29 | * Annotation specifying the [[org.springframework.scala.context.function.FunctionalConfiguration]] classes that 30 | * should be loaded for a Spring Test [[org.springframework.context.ApplicationContext]]. Used in conjunction with 31 | * [[org.springframework.scala.test.context.FunctionalConfigContextLoader]]. 32 | * 33 | * @param classes [[org.springframework.scala.context.function.FunctionalConfiguration]] definitions that should be 34 | * loaded by the Spring Test [[org.springframework.context.ApplicationContext]]. 35 | * 36 | * @author Henryk Konsek 37 | */ 38 | case class FunctionalConfigurations(classes: Class[_ <: FunctionalConfiguration]*) extends StaticAnnotation 39 | 40 | /** 41 | * Companion object for [[org.springframework.scala.test.context.FunctionalConfigurations]] annotation. Contains 42 | * mainly miscellaneous helper methods. 43 | * 44 | * @author Henryk Konsek 45 | */ 46 | object FunctionalConfigurations { 47 | 48 | /** 49 | * Retrieves the [[org.springframework.scala.context.function.FunctionalConfiguration]] classes definitions from the 50 | * test class annotated with the [[org.springframework.scala.test.context.FunctionalConfigurations]]. 51 | * 52 | * @param testClass test class to be examined (annotated with the 53 | * [[org.springframework.scala.test.context.FunctionalConfigurations]]). 54 | * @return Sequence of [[org.springframework.scala.context.function.FunctionalConfiguration]]s extracted from the 55 | * [[org.springframework.scala.test.context.FunctionalConfigurations]] annotation. Empty sequence if no 56 | * functional configuration class has been provided or 57 | * [[org.springframework.scala.test.context.FunctionalConfigurations]] annotation is missing. 58 | */ 59 | def resolveConfigurationsFromTestClass(testClass: Class[_]): Seq[Class[_ <: FunctionalConfiguration]] = { 60 | val mirror = runtimeMirror(defaultClassLoader) 61 | val configurationsAnnotationType = typeOf[FunctionalConfigurations] 62 | val testClassSymbol = mirror.classSymbol(testClass) 63 | 64 | testClassSymbol.annotations.find(_.tree.tpe == configurationsAnnotationType) match { 65 | case Some(annotation) => { 66 | val configurationsAnnotationArgs = annotation.tree.children.tail.map { 67 | arg => mirror.runtimeClass(arg.productElement(0).asInstanceOf[Constant].value.asInstanceOf[TypeRef]) 68 | } 69 | val annotationMirror = mirror.reflectClass(configurationsAnnotationType.typeSymbol.asClass) 70 | val constructorSymbol = configurationsAnnotationType.decl(termNames.CONSTRUCTOR).asMethod 71 | val constructorMirror = annotationMirror.reflectConstructor(constructorSymbol) 72 | constructorMirror(configurationsAnnotationArgs.seq).asInstanceOf[FunctionalConfigurations].classes 73 | } 74 | case None => Seq() 75 | } 76 | } 77 | 78 | } -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/transaction/function/TransactionMode.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.transaction.function 18 | 19 | /** 20 | * Base class for annotation-driven transaction manager modes: 21 | * [[org.springframework.scala.transaction.function.AspectJTransactionMode]] 22 | * and 23 | * [[org.springframework.scala.transaction.function.ProxyTransactionMode]] 24 | * 25 | * @author Maciej Zientarski 26 | * @since 1.0 27 | */ 28 | abstract class TransactionMode 29 | 30 | /** 31 | * AspectJ annotation-driven transaction manager mode. To be used as parameter of 32 | * `org.springframework.scala.context.function.TransactionSupport.enableTransactionManagement()` 33 | * 34 | * @author Maciej Zientarski 35 | * @since 1.0 36 | */ 37 | case class AspectJTransactionMode() extends TransactionMode 38 | 39 | /** 40 | * Spring's AOP framework proxy transaction mode. To be used as 41 | * parameter of [[org.springframework.scala.transaction.function.TransactionSupport.enableTransactionManagement( )]] 42 | * Equivalent to `mode="proxy"` attribute of ``. 43 | * 44 | * @param proxyTargetClass equivalent to `proxy-target-class="true|false"` attribute of 45 | * ``. If set to true, then class based proxies are used. 46 | * False means that standard JDK interface-based proxies should be created. 47 | * @author Maciej Zientarski 48 | * @since 1.0 49 | */ 50 | case class ProxyTransactionMode(proxyTargetClass: Boolean = false) extends TransactionMode -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/transaction/function/TransactionSupport.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.transaction.function 18 | 19 | import org.springframework.scala.context.function.FunctionalConfiguration 20 | import org.springframework.transaction.config.TransactionManagementConfigUtils 21 | import org.springframework.beans.factory.support.{BeanNameGenerator, BeanDefinitionReaderUtils, RootBeanDefinition} 22 | import org.springframework.beans.factory.parsing.BeanComponentDefinition 23 | import org.springframework.beans.factory.config.{RuntimeBeanReference, BeanDefinition} 24 | import org.springframework.aop.config.AopConfigUtils 25 | import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource 26 | import org.springframework.transaction.interceptor.{BeanFactoryTransactionAttributeSourceAdvisor, TransactionInterceptor} 27 | import org.springframework.context.support.GenericApplicationContext 28 | 29 | /** 30 | * Defines additional FunctionalConfiguration elements for transaction support . 31 | * 32 | * @author Maciej Zientarski 33 | * @since 1.0 34 | * @see FunctionalConfiguration 35 | */ 36 | trait TransactionSupport { 37 | self: FunctionalConfiguration => 38 | 39 | /** 40 | * Enables annotation-driven transaction management. Equivalent to `` 41 | * and [[org.springframework.transaction.annotation.EnableTransactionManagement]] annotation. 42 | * Adds transactions around calls to methods annotated with @Transactional. 43 | * Should be used as follows: 44 | * {{{ 45 | * class Config extends FunctionalConfiguration with TransactionSupport { 46 | * enableTransactionManagement() 47 | * } 48 | * }}} 49 | * which is equivalent to 50 | * {{{ 51 | * 52 | * 53 | * 54 | * }}} 55 | * and 56 | * {{{ 57 | * @Configuration 58 | * @EnableTransactionManagement 59 | * public class Config {} 60 | * }}} 61 | * 62 | * @param transactionMode one of [[org.springframework.scala.context.function.AspectJTransactionMode]] 63 | * or [[org.springframework.scala.context.function.ProxyTransactionMode]]. Defaults to 64 | * `ProxyTransactionMode` 65 | * @param transactionManagerName transaction manager bean name. 66 | * Defaults to `TransactionSupport.DEFAULT_TRANSACTION_MANAGER_NAME` 67 | * @param order order of transaction advice applied to `@Transactional` methods 68 | */ 69 | def enableTransactionManagement( 70 | transactionMode: TransactionMode = ProxyTransactionMode(), 71 | transactionManagerName: String = TransactionSupport.DEFAULT_TRANSACTION_MANAGER_NAME, 72 | order: Int = org.springframework.core.Ordered.LOWEST_PRECEDENCE 73 | ) { 74 | 75 | def setupAspectJTransactions() { 76 | val txAspectBeanName = TransactionManagementConfigUtils.TRANSACTION_ASPECT_BEAN_NAME 77 | val txAspectClassName = TransactionManagementConfigUtils.TRANSACTION_ASPECT_CLASS_NAME 78 | 79 | if (!beanRegistry.containsBeanDefinition(txAspectBeanName)) { 80 | val rootBeanDefinition = new RootBeanDefinition() 81 | rootBeanDefinition.setBeanClassName(txAspectClassName) 82 | rootBeanDefinition.setFactoryMethodName("aspectOf") 83 | rootBeanDefinition.getPropertyValues.add("transactionManagerBeanName", transactionManagerName) 84 | BeanDefinitionReaderUtils.registerBeanDefinition( 85 | new BeanComponentDefinition(rootBeanDefinition, txAspectBeanName), 86 | beanRegistry 87 | ) 88 | } 89 | } 90 | 91 | def setupProxyTransactions(proxyTargetClass: Boolean, beanNameGenerator: BeanNameGenerator) { 92 | 93 | def registerWithGeneratedName(beanDefinition: BeanDefinition) = { 94 | val generatedName = beanNameGenerator.generateBeanName(beanDefinition, beanRegistry) 95 | beanRegistry.registerBeanDefinition(generatedName, beanDefinition) 96 | generatedName 97 | } 98 | 99 | AopConfigUtils.registerAutoProxyCreatorIfNecessary(beanRegistry, null) 100 | if (proxyTargetClass) { 101 | AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(beanRegistry) 102 | } 103 | 104 | if (!beanRegistry.containsBeanDefinition( 105 | TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)) { 106 | 107 | // Create the TransactionAttributeSource definition. 108 | val sourceDef = new RootBeanDefinition(Predef.classOf[AnnotationTransactionAttributeSource]) 109 | sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE) 110 | val sourceName = registerWithGeneratedName(sourceDef) 111 | 112 | // Create the TransactionInterceptor definition. 113 | val interceptorDef = new RootBeanDefinition(Predef.classOf[TransactionInterceptor]) 114 | interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE) 115 | interceptorDef.getPropertyValues.add("transactionManagerBeanName", 116 | transactionManagerName) 117 | interceptorDef.getPropertyValues.add("transactionAttributeSource", 118 | new RuntimeBeanReference(sourceName)) 119 | val interceptorName = registerWithGeneratedName(interceptorDef) 120 | 121 | // Create the TransactionAttributeSourceAdvisor definition. 122 | val advisorDef = new RootBeanDefinition(Predef.classOf[BeanFactoryTransactionAttributeSourceAdvisor]) 123 | advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE) 124 | advisorDef.getPropertyValues.add("transactionAttributeSource", 125 | new RuntimeBeanReference(sourceName)) 126 | advisorDef.getPropertyValues.add("advice", new RuntimeBeanReference(interceptorName)) 127 | advisorDef.getPropertyValues.add("adviceBeanName", interceptorName) 128 | advisorDef.getPropertyValues.add("order", order.toString) 129 | beanRegistry.registerBeanDefinition( 130 | TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME, advisorDef) 131 | } 132 | } 133 | 134 | onRegister((applicationContext: GenericApplicationContext, 135 | beanNameGenerator: BeanNameGenerator) => 136 | transactionMode match { 137 | case ProxyTransactionMode(proxyTargetClass) => 138 | setupProxyTransactions(proxyTargetClass, beanNameGenerator) 139 | case _ => 140 | setupAspectJTransactions() 141 | }) 142 | } 143 | } 144 | 145 | /** 146 | * Used to store default transaction manager name. 147 | * 148 | * @author Maciej Zientarski 149 | * @since 1.0 150 | */ 151 | object TransactionSupport { 152 | val DEFAULT_TRANSACTION_MANAGER_NAME = "transactionManager" 153 | } -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/transaction/support/SynchronizationEvent.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.transaction.support 18 | 19 | /** 20 | * Base trait for the events triggered by the Spring 21 | * [[org.springframework.transaction.support.TransactionSynchronizationManager]]. 22 | * 23 | * @author Henryk Konsek 24 | * @since 1.0 25 | */ 26 | sealed trait SynchronizationEvent 27 | 28 | /** 29 | * Event generated when the `suspend` method of the 30 | * [[org.springframework.transaction.support.TransactionSynchronization]] callback is executed. 31 | * 32 | * @author Henryk Konsek 33 | * @since 1.0 34 | */ 35 | case object SuspendEvent extends SynchronizationEvent 36 | 37 | /** 38 | * Event generated when the `resume` method of the 39 | * [[org.springframework.transaction.support.TransactionSynchronization]] callback is executed. 40 | * 41 | * @author Henryk Konsek 42 | * @since 1.0 43 | */ 44 | case object ResumeEvent extends SynchronizationEvent 45 | 46 | /** 47 | * Event generated when the `flush` method of the 48 | * [[org.springframework.transaction.support.TransactionSynchronization]] callback is executed. 49 | * 50 | * @author Henryk Konsek 51 | * @since 1.0 52 | */ 53 | case object FlushEvent extends SynchronizationEvent 54 | 55 | /** 56 | * Event generated when the `beforeCommit` method of the 57 | * [[org.springframework.transaction.support.TransactionSynchronization]] callback is executed. 58 | * 59 | * @author Henryk Konsek 60 | * @since 1.0 61 | * @param readOnly whether the synchronized transaction is defined as read-only transaction 62 | */ 63 | case class BeforeCommitEvent(readOnly: Boolean) extends SynchronizationEvent 64 | 65 | /** 66 | * Event generated when the `beforeCompletion` method of the 67 | * [[org.springframework.transaction.support.TransactionSynchronization]] callback is executed. 68 | * 69 | * @author Henryk Konsek 70 | * @since 1.0 71 | */ 72 | case object BeforeCompletionEvent extends SynchronizationEvent 73 | 74 | /** 75 | * Event generated when the `afterCommit` method of the 76 | * [[org.springframework.transaction.support.TransactionSynchronization]] callback is executed. 77 | * 78 | * @author Henryk Konsek 79 | * @since 1.0 80 | */ 81 | case object AfterCommitEvent extends SynchronizationEvent 82 | 83 | /** 84 | * Event generated when the `afterCompletion` method of the 85 | * [[org.springframework.transaction.support.TransactionSynchronization]] callback is executed. 86 | * 87 | * @author Henryk Konsek 88 | * @since 1.0 89 | * @param status completion status according to the `TransactionSynchronization.STATUS_*` constant 90 | */ 91 | case class AfterCompletionEvent(status: Int) extends SynchronizationEvent 92 | -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/transaction/support/TransactionManagement.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.transaction.support 18 | 19 | import org.springframework.transaction.annotation.{Isolation, Propagation} 20 | import org.springframework.transaction.support.TransactionCallback 21 | import org.springframework.transaction.{TransactionStatus, TransactionDefinition, PlatformTransactionManager} 22 | import org.springframework.transaction.interceptor.DefaultTransactionAttribute 23 | 24 | /** 25 | * Trait that simplifies functional transaction demarcation and transaction exception handling. 26 | * 27 | * The central entry point is the `transactional` function. This trait handles the transaction lifecycle and possible 28 | * exceptions such that neither the function nor the calling code needs to explicitly handle transactions. 29 | * 30 | * @author Arjen Poutsma 31 | * @since 1.0 32 | */ 33 | trait TransactionManagement { 34 | 35 | /** 36 | * The transaction management strategy to be used 37 | */ 38 | val transactionManager: PlatformTransactionManager 39 | 40 | /** 41 | * Execute the given function within a transaction. 42 | * 43 | * @tparam T the return type of the function 44 | * @param function the function to be executed transactionally 45 | * @param propagation the propagation behavior. Defaults to `REQUIRED` 46 | * @param isolation the isolation level. Defaults to `DEFAULT` 47 | * @param readOnly whether to optimize as a read-only transaction. Defaults to `false`. 48 | * @param qualifier qualifier value for the specified transaction. Defaults to none. 49 | * @param timeout timeout for this transaction. Defaults to the default timeout of the underlying transaction 50 | * system. 51 | * @return a result object returned by the function 52 | * @throws TransactionException in case of initialization, rollback, or system errors 53 | */ 54 | def transactional[T](propagation: Propagation = Propagation.REQUIRED, 55 | isolation: Isolation = Isolation.DEFAULT, 56 | readOnly: Boolean = false, 57 | qualifier: String = "", 58 | timeout: Int = TransactionDefinition.TIMEOUT_DEFAULT)(function: TransactionStatus => T): T = { 59 | 60 | val transactionAttribute = new DefaultTransactionAttribute() 61 | transactionAttribute.setPropagationBehavior(propagation.value()) 62 | transactionAttribute.setIsolationLevel(isolation.value()) 63 | transactionAttribute.setTimeout(timeout) 64 | transactionAttribute.setReadOnly(readOnly) 65 | transactionAttribute.setQualifier(qualifier) 66 | 67 | val template = new org.springframework.transaction.support.TransactionTemplate(transactionManager, 68 | transactionAttribute) 69 | template.execute(new TransactionCallback[T] { 70 | def doInTransaction(status: TransactionStatus) = function(status) 71 | }) 72 | } 73 | 74 | 75 | } -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/transaction/support/TransactionSynchronizationManager.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.transaction.support 18 | 19 | import org.springframework.transaction.support.TransactionSynchronization 20 | import org.springframework.transaction.support.{TransactionSynchronizationManager => DelegateSynchronizationManager} 21 | 22 | /** 23 | * Scala-based convenience wrapper for the Spring 24 | * [[org.springframework.transaction.support.TransactionSynchronizationManager]], providing pattern matching style 25 | * callbacks. 26 | * 27 | * @author Henryk Konsek 28 | * @since 1.0 29 | */ 30 | object TransactionSynchronizationManager { 31 | 32 | /** 33 | * Register partial function delegate for the [[org.springframework.transaction.support.TransactionSynchronization]] 34 | * callbacks. 35 | * 36 | * @param synchronization partial function representing callback to be executed when particular 37 | * [[org.springframework.scala.transaction.support.SynchronizationEvent]] is fired. 38 | */ 39 | def registerSynchronization(synchronization: PartialFunction[SynchronizationEvent, Unit]) { 40 | def propagateEvent(e: SynchronizationEvent) { 41 | if (synchronization.isDefinedAt(e)) 42 | synchronization(e) 43 | } 44 | 45 | DelegateSynchronizationManager.registerSynchronization(new TransactionSynchronization() { 46 | def suspend() { 47 | propagateEvent(SuspendEvent) 48 | } 49 | 50 | def resume() { 51 | propagateEvent(ResumeEvent) 52 | } 53 | 54 | def flush() { 55 | propagateEvent(FlushEvent) 56 | } 57 | 58 | def beforeCommit(readOnly: Boolean) { 59 | propagateEvent(BeforeCommitEvent(readOnly)) 60 | } 61 | 62 | def beforeCompletion() { 63 | propagateEvent(BeforeCompletionEvent) 64 | } 65 | 66 | def afterCommit() { 67 | propagateEvent(AfterCommitEvent) 68 | } 69 | 70 | def afterCompletion(status: Int) { 71 | propagateEvent(AfterCompletionEvent(status)) 72 | } 73 | }) 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/transaction/support/TransactionTemplate.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.transaction.support 18 | 19 | import org.springframework.transaction.support.{TransactionCallback, TransactionOperations} 20 | import org.springframework.transaction.{TransactionDefinition, PlatformTransactionManager, TransactionStatus} 21 | 22 | /** 23 | * Scala-based convenience wrapper for the Spring 24 | * [[org.springframework.scala.transaction.support.TransactionTemplate]], taking 25 | * advantage of functions and Scala types. 26 | * 27 | * @author Arjen Poutsma 28 | * @since 1.0 29 | * @constructor Creates a `TransactionTemplate` that wraps the given Java template 30 | * @param javaTemplate the Java `TransactionTemplate` to wrap 31 | */ 32 | class TransactionTemplate(val javaTemplate: TransactionOperations) { 33 | 34 | def this(transactionManager: PlatformTransactionManager) { 35 | this (new org.springframework.transaction.support.TransactionTemplate(transactionManager)) 36 | } 37 | 38 | /** 39 | * Construct a new TransactionTemplate using the given transaction manager, 40 | * taking its default settings from the given transaction definition. 41 | * @param transactionManager the transaction management strategy to be used 42 | * @param transactionDefinition the transaction definition to copy the default settings from. Local properties can still be set to change values. 43 | */ 44 | def this(transactionManager: PlatformTransactionManager, transactionDefinition: TransactionDefinition) { 45 | this (new org.springframework.transaction.support.TransactionTemplate(transactionManager, transactionDefinition)) 46 | } 47 | 48 | /** 49 | * Execute the action specified by the given function within a transaction. 50 | *

Allows for returning a result object created within the transaction, that is, 51 | * a domain object or a collection of domain objects. A RuntimeException thrown 52 | * by the callback is treated as a fatal exception that enforces a rollback. 53 | * Such an exception gets propagated to the caller of the template. 54 | * @param action the callback object that specifies the transactional action 55 | * @return a result object returned by the callback, or null if none 56 | * @throws TransactionException in case of initialization, rollback, or system errors 57 | */ 58 | def execute[T](action: TransactionStatus => T): T = { 59 | javaTemplate.execute(new TransactionCallback[T] { 60 | def doInTransaction(status: TransactionStatus) = { 61 | action.apply(status) 62 | } 63 | }) 64 | } 65 | 66 | } -------------------------------------------------------------------------------- /src/main/scala/org/springframework/scala/util/TypeTagUtils.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.util 18 | 19 | import scala.reflect.ClassTag 20 | import scala.reflect.classTag 21 | 22 | /** 23 | * Miscellaneous ``TypeTag`` (and ``ClassTag``) utility methods for internal use within the 24 | * framework. 25 | * 26 | * @author Henryk Konsek 27 | */ 28 | private[springframework] object TypeTagUtils { 29 | 30 | /** 31 | * Returns the [[java.lang.Class]] corresponding to the given class tag. 32 | * 33 | * @param tag the class tag to convert 34 | * @tparam T the tag's bound type 35 | * @return the runtime class of the tag 36 | */ 37 | def tagToClass[T](tag: ClassTag[T]): Class[T] = { 38 | tag.runtimeClass.asInstanceOf[Class[T]] 39 | } 40 | 41 | /** 42 | * Returns the [[java.lang.Class]] corresponding to the given type. 43 | * 44 | * @tparam T the bound type to convert 45 | * @return the runtime class of the given type 46 | */ 47 | def typeToClass[T: ClassTag]: Class[T] = { 48 | tagToClass(classTag[T]) 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/scala/context/function/MyAnnotatedConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.context.function; 18 | 19 | import org.springframework.context.annotation.Bean; 20 | import org.springframework.context.annotation.Configuration; 21 | 22 | @Configuration 23 | public class MyAnnotatedConfiguration { 24 | 25 | @Bean 26 | public String firstName() { 27 | return "John"; 28 | } 29 | 30 | @Bean 31 | public String lastName() { 32 | return "Doe"; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/resources/data.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO USERS(ID, FIRST_NAME, LAST_NAME) VALUES (1, 'John', 'Doe') 2 | INSERT INTO USERS(ID, FIRST_NAME, LAST_NAME) VALUES (2, 'Jane', 'Doe') -------------------------------------------------------------------------------- /src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootCategory=INFO, stdout 2 | log4j.logger.org.springframework.scala=DEBUG 3 | 4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 6 | log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n -------------------------------------------------------------------------------- /src/test/resources/org/springframework/scala/beans/factory/xml/utilNamespaceHandlerTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | one 16 | two 17 | 18 | 19 | 20 | one 21 | two 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/test/resources/org/springframework/scala/beans/propertyeditors/scalaEditorRegistrarTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | one 58 | two 59 | three 60 | 61 | 62 | 63 | one 64 | two 65 | three 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/test/resources/org/springframework/scala/beans/scalaBeanInfoFactoryIntegrationTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/test/resources/org/springframework/scala/context/function/imported.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/test/resources/schema.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE USERS IF EXISTS; 2 | 3 | CREATE TABLE USERS( 4 | ID IDENTITY NOT NULL PRIMARY KEY, 5 | FIRST_NAME VARCHAR(25) NOT NULL, 6 | LAST_NAME VARCHAR(25) NOT NULL 7 | ); 8 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/aop/AdviceConversionsTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.aop 18 | 19 | import org.springframework.context.support.GenericApplicationContext 20 | import org.scalatest.FunSuite 21 | import org.junit.runner.RunWith 22 | import org.scalatest.junit.JUnitRunner 23 | import org.springframework.scala.context.function.FunctionalConfigApplicationContext 24 | 25 | @RunWith(classOf[JUnitRunner]) 26 | class AdviceConversionsTests extends FunSuite { 27 | 28 | val applicationContext: GenericApplicationContext = FunctionalConfigApplicationContext[MethodAdviceConfiguration] 29 | 30 | test("MethodAdvice#interceptor") { 31 | val intercepted = applicationContext.getBean("intercepted") 32 | val toStringResult = intercepted.toString 33 | assert("intercepted" eq toStringResult) 34 | } 35 | 36 | test("MethodAdvice#before") { 37 | val beforeAdviced = applicationContext.getBean("advicedBefore") 38 | intercept[BeforeAdviceException](beforeAdviced.toString) 39 | } 40 | 41 | test("MethodAdvice#after") { 42 | val advicedAfter = applicationContext.getBean("advicedAfter") 43 | intercept[AfterAdviceException](advicedAfter.toString) 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/aop/MethodAdviceConfiguration.scala: -------------------------------------------------------------------------------- 1 | package org.springframework.scala.aop 2 | 3 | import org.springframework.scala.context.function.FunctionalConfiguration 4 | import org.springframework.aop.framework.ProxyFactory 5 | 6 | import AdviceConversions._ 7 | import java.lang.reflect.Method 8 | import org.springframework.aop.AfterReturningAdvice 9 | import org.aopalliance.intercept.{MethodInvocation, MethodInterceptor} 10 | 11 | class MethodAdviceConfiguration extends FunctionalConfiguration { 12 | 13 | val interceptor = bean[MethodInterceptor]("interceptor") { 14 | (methodInvocation: MethodInvocation) => "intercepted" 15 | } 16 | 17 | bean("intercepted") { 18 | val factory = new ProxyFactory(classOf[Object]) 19 | factory.addAdvice(interceptor()) 20 | factory.getProxy 21 | } 22 | 23 | bean("advicedBefore") { 24 | val factory = new ProxyFactory(classOf[Object]) 25 | factory.addAdvice((method: Method, args: Array[AnyRef], target: Any) => throw new BeforeAdviceException) 26 | factory.getProxy 27 | } 28 | 29 | val afterReturningAdvice = bean[AfterReturningAdvice]("afterReturningAdvice") { 30 | (returned: Any, method: Method, args: Array[AnyRef], target: Any) => throw new AfterAdviceException 31 | } 32 | 33 | bean("advicedAfter") { 34 | val factory = new ProxyFactory(classOf[Object]) 35 | factory.addAdvice(afterReturningAdvice()) 36 | factory.getProxy 37 | } 38 | 39 | } 40 | 41 | class BeforeAdviceException extends RuntimeException 42 | 43 | class AfterAdviceException extends RuntimeException -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/beans/ScalaBean.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans 18 | 19 | import scala.beans.BeanProperty 20 | 21 | class ScalaBean { 22 | 23 | val readOnly: String = "Foo" 24 | 25 | var readWrite: String = "Foo" 26 | 27 | @BeanProperty 28 | var beanProperty: String = "Foo" 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/beans/ScalaBeanInfoFactoryTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans 18 | 19 | import org.scalatest.FunSuite 20 | import org.springframework.beans.factory.support.DefaultListableBeanFactory 21 | import org.springframework.beans.factory.xml.XmlBeanDefinitionReader 22 | import org.springframework.core.io.ClassPathResource 23 | import org.junit.runner.RunWith 24 | import org.scalatest.junit.JUnitRunner 25 | 26 | /** 27 | * @author Arjen Poutsma 28 | */ 29 | @RunWith(classOf[JUnitRunner]) 30 | class ScalaBeanInfoFactoryTests extends FunSuite { 31 | 32 | test("registration") { 33 | val beanFactory = new DefaultListableBeanFactory 34 | val reader = new XmlBeanDefinitionReader(beanFactory) 35 | 36 | reader.loadBeanDefinitions(new ClassPathResource( 37 | "scalaBeanInfoFactoryIntegrationTest.xml", getClass)) 38 | 39 | val bean = beanFactory.getBean("scalaBean", classOf[ScalaBean]) 40 | 41 | assert("Bar" === bean.readWrite) 42 | assert("Bar" === bean.getBeanProperty) 43 | } 44 | 45 | test("supports") { 46 | val factory = new ScalaBeanInfoFactory 47 | assert(null != factory.getBeanInfo(classOf[ScalaBean])) 48 | assert(null == factory.getBeanInfo(classOf[Object])) 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/beans/ScalaBeanInfoTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans 18 | 19 | import org.scalatest.FunSuite 20 | import org.junit.runner.RunWith 21 | import org.scalatest.junit.JUnitRunner 22 | 23 | /** 24 | * @author Arjen Poutsma 25 | */ 26 | @RunWith(classOf[JUnitRunner]) 27 | class ScalaBeanInfoTests extends FunSuite { 28 | 29 | test("propertyDescriptors") { 30 | val beanInfo = new ScalaBeanInfo(classOf[ScalaBean]) 31 | 32 | val propertyDescriptors = beanInfo.getPropertyDescriptors 33 | 34 | assert(4 === propertyDescriptors.length) 35 | 36 | assert("beanProperty" === propertyDescriptors(0).getName) 37 | assert("getBeanProperty" === propertyDescriptors(0).getReadMethod.getName) 38 | assert("setBeanProperty" === propertyDescriptors(0).getWriteMethod.getName) 39 | 40 | 41 | assert("class" === propertyDescriptors(1).getName) 42 | 43 | assert("readOnly" === propertyDescriptors(2).getName) 44 | assert("readOnly" === propertyDescriptors(2).getReadMethod.getName) 45 | assert(null == propertyDescriptors(2).getWriteMethod) 46 | 47 | assert("readWrite" === propertyDescriptors(3).getName) 48 | assert("readWrite" === propertyDescriptors(3).getReadMethod.getName) 49 | assert("readWrite_$eq" === propertyDescriptors(3).getWriteMethod.getName) 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/beans/factory/RichBeanFactoryTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory 18 | 19 | import org.springframework.beans.factory.support.StaticListableBeanFactory 20 | import org.scalatest.FunSuite 21 | import BeanFactoryConversions._ 22 | import org.junit.runner.RunWith 23 | import org.scalatest.junit.JUnitRunner 24 | 25 | /** 26 | * @author Arjen Poutsma 27 | */ 28 | @RunWith(classOf[JUnitRunner]) 29 | class RichBeanFactoryTests extends FunSuite { 30 | 31 | val beanFactory = new StaticListableBeanFactory() 32 | beanFactory.addBean("foo", "Bar") 33 | 34 | test("bean()") { 35 | val result = beanFactory.bean[String] 36 | assert("Bar" === result.get) 37 | } 38 | 39 | test("bean() not present") { 40 | val result = beanFactory.bean[Boolean] 41 | assert(None === result) 42 | } 43 | 44 | test("apply[T]()") { 45 | val result = beanFactory[String] 46 | assert("Bar" === result) 47 | } 48 | 49 | test("bean[T](String)") { 50 | val result = beanFactory.bean[String]("foo") 51 | assert("Bar" === result.get) 52 | } 53 | 54 | test("bean[T](String) not present") { 55 | val result = beanFactory.bean[String]("bar") 56 | assert(None === result) 57 | } 58 | 59 | test("apply[T](String)") { 60 | val result = beanFactory[String]("foo") 61 | assert("Bar" === result) 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/beans/factory/RichListableBeanFactoryTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory 18 | 19 | import org.scalatest.FunSuite 20 | import org.springframework.beans.factory.support.StaticListableBeanFactory 21 | import BeanFactoryConversions._ 22 | import org.scalatest.junit.JUnitRunner 23 | import org.junit.runner.RunWith 24 | 25 | /** 26 | * @author Arjen Poutsma 27 | */ 28 | @RunWith(classOf[JUnitRunner]) 29 | class RichListableBeanFactoryTests extends FunSuite { 30 | 31 | val bean = new MyBean 32 | 33 | val beanFactory = new StaticListableBeanFactory 34 | beanFactory.addBean("bean", bean) 35 | 36 | test("getBeanNamesForType") { 37 | val result = beanFactory.beanNamesForType[MyBean]() 38 | 39 | assert(1 == result.size) 40 | assert("bean" === result(0)) 41 | } 42 | 43 | test("getBeansOfType") { 44 | val result = beanFactory.beansOfType[MyBean]() 45 | 46 | assert(1 == result.size) 47 | assert(bean === result("bean")) 48 | } 49 | 50 | class MyBean 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/beans/factory/annotation/ConstructorAutowiredAnnotationBeanPostProcessorTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory.annotation 18 | 19 | import javax.inject.Inject 20 | import org.junit.runner.RunWith 21 | import org.scalatest.FunSuite 22 | import org.scalatest.junit.JUnitRunner 23 | import org.springframework.beans.factory.annotation.Autowired 24 | 25 | /** @author Stephen Samuel */ 26 | @RunWith(classOf[JUnitRunner]) 27 | class ConstructorAutowiredAnnotationBeanPostProcessorTests extends FunSuite { 28 | 29 | val processor = new ConstructorAutowiredAnnotationBeanPostProcessor 30 | 31 | test("none") { 32 | val result = processor.determineCandidateConstructors(classOf[NoAutowiredWithConstructor], "name") 33 | assert(result === null) 34 | } 35 | 36 | test("autowired") { 37 | val result = processor.determineCandidateConstructors(classOf[AutowiredWithConstructor], "name") 38 | assert(result.size === 1) 39 | assert(result(0).getParameterTypes()(0) === classOf[String]) 40 | } 41 | 42 | test("inject") { 43 | val result = processor.determineCandidateConstructors(classOf[InjectWithConstructor], "name") 44 | assert(result.size === 1) 45 | assert(result(0).getParameterTypes()(0) === classOf[String]) 46 | } 47 | 48 | test("two constructors") { 49 | val result = processor 50 | .determineCandidateConstructors(classOf[AutowiredWithTwoConstructors], "name") 51 | assert(result === null) 52 | } 53 | } 54 | 55 | class NoAutowiredWithConstructor(name: String) {} 56 | 57 | @Autowired 58 | class AutowiredWithConstructor(name: String) {} 59 | 60 | @Inject 61 | class InjectWithConstructor(name: String) {} 62 | 63 | @Autowired 64 | class AutowiredWithTwoConstructors(name: String) { 65 | def this(name: String, age: Int) { 66 | this(name) 67 | } 68 | } 69 | 70 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/beans/factory/function/FunctionalRootBeanDefinitionTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory.function 18 | 19 | import org.springframework.context.support.StaticApplicationContext 20 | import org.springframework.beans.factory.config.BeanDefinition 21 | import org.scalatest.{BeforeAndAfterEach, FunSuite} 22 | import org.junit.runner.RunWith 23 | import org.scalatest.junit.JUnitRunner 24 | 25 | /** 26 | * @author Arjen Poutsma 27 | */ 28 | @RunWith(classOf[JUnitRunner]) 29 | class FunctionalRootBeanDefinitionTests extends FunSuite with BeforeAndAfterEach { 30 | 31 | val applicationContext = new StaticApplicationContext() 32 | 33 | var n: Int = 0 34 | 35 | val beanFunction = () => { 36 | n += 1 37 | n 38 | } 39 | 40 | override protected def beforeEach() { 41 | n = 0 42 | } 43 | 44 | test("singleton") { 45 | val bd = new FunctionalRootBeanDefinition[Int](beanFunction, classOf[Int]) 46 | bd.setScope(BeanDefinition.SCOPE_SINGLETON) 47 | applicationContext.registerBeanDefinition("function", bd) 48 | 49 | val value1 = applicationContext.getBean("function") 50 | val value2 = applicationContext.getBean("function") 51 | 52 | assert(value1 == value2) 53 | assert(n == 1) 54 | 55 | } 56 | 57 | test("prototype") { 58 | val bd = new FunctionalRootBeanDefinition[Int](beanFunction, classOf[Int]) 59 | bd.setScope(BeanDefinition.SCOPE_PROTOTYPE) 60 | applicationContext.registerBeanDefinition("function", bd) 61 | 62 | val value1 = applicationContext.getBean("function") 63 | val value2 = applicationContext.getBean("function") 64 | 65 | assert(value1 != value2) 66 | assert(n == 2) 67 | } 68 | } 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/beans/factory/function/InitDestroyFunctionBeanPostProcessorTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.factory.function 18 | 19 | import org.scalatest.FunSuite 20 | import org.junit.runner.RunWith 21 | import org.scalatest.junit.JUnitRunner 22 | 23 | /** 24 | * @author Arjen Poutsma 25 | */ 26 | @RunWith(classOf[JUnitRunner]) 27 | class InitDestroyFunctionBeanPostProcessorTests extends FunSuite { 28 | 29 | val bpp = new InitDestroyFunctionBeanPostProcessor 30 | 31 | test("initFunctions") { 32 | val beanName = "foo" 33 | val bean = "bar" 34 | 35 | var function1Invoked = false 36 | var function2Invoked = false 37 | 38 | bpp.registerInitFunction(beanName, (s: String) => { 39 | assert(!function2Invoked) 40 | function1Invoked = true 41 | }) 42 | bpp.registerInitFunction(beanName, (s: String) => { 43 | assert(function1Invoked) 44 | function2Invoked = true 45 | }) 46 | 47 | val result = bpp.postProcessBeforeInitialization(bean, beanName) 48 | 49 | assert(result eq bean) 50 | assert(function1Invoked) 51 | assert(function2Invoked) 52 | } 53 | 54 | test("destroyFunctions") { 55 | val beanName = "foo" 56 | var function1Invoked = false 57 | var function2Invoked = false 58 | 59 | bpp.registerDestroyFunction(beanName, (s: String) => { 60 | assert(!function2Invoked) 61 | function1Invoked = true 62 | }) 63 | bpp.registerDestroyFunction(beanName, (s: String) => { 64 | assert(function1Invoked) 65 | function2Invoked = true 66 | }) 67 | 68 | bpp.postProcessBeforeDestruction("bar", beanName) 69 | 70 | assert(function1Invoked) 71 | assert(function2Invoked) 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/beans/factory/xml/UtilNamespaceHandlerTests.scala: -------------------------------------------------------------------------------- 1 | package org.springframework.scala.beans.factory.xml 2 | 3 | import org.scalatest.FunSuite 4 | import org.springframework.context.support.ClassPathXmlApplicationContext 5 | import org.junit.runner.RunWith 6 | import org.scalatest.junit.JUnitRunner 7 | 8 | /** 9 | * @author Arjen Poutsma 10 | */ 11 | @RunWith(classOf[JUnitRunner]) 12 | class UtilNamespaceHandlerTests extends FunSuite { 13 | 14 | val applicationContext = new ClassPathXmlApplicationContext("utilNamespaceHandlerTest.xml", getClass) 15 | 16 | test("seq") { 17 | val seq = applicationContext.getBean("seq", classOf[scala.collection.Seq[String]]) 18 | assert(seq != null) 19 | assert(seq.size == 2) 20 | assert(seq.contains("one")) 21 | assert(seq.contains("two")) 22 | } 23 | 24 | test("set") { 25 | val set = applicationContext.getBean("set", classOf[scala.collection.Set[String]]) 26 | assert(set != null) 27 | assert(set.size == 2) 28 | assert(set.contains("one")) 29 | assert(set.contains("two")) 30 | } 31 | 32 | test("map") { 33 | val map = applicationContext.getBean("map", classOf[scala.collection.Map[String, String]]) 34 | assert(map != null) 35 | assert(map.size == 1) 36 | assert(map.contains("one")) 37 | assert(map("one") == "two") 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/beans/propertyeditors/CollectionsBean.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.propertyeditors 18 | 19 | import scala.beans.BeanProperty 20 | 21 | class CollectionsBean { 22 | 23 | @BeanProperty 24 | var seq: scala.collection.Seq[String] = null 25 | 26 | @BeanProperty 27 | var immutableSeq: scala.collection.immutable.Seq[String] = null 28 | 29 | @BeanProperty 30 | var mutableSeq: scala.collection.mutable.Seq[String] = null 31 | 32 | @BeanProperty 33 | var indexedSeq: scala.collection.IndexedSeq[String] = null 34 | 35 | @BeanProperty 36 | var immutableIndexedSeq: scala.collection.immutable.IndexedSeq[String] = null 37 | 38 | @BeanProperty 39 | var mutableIndexedSeq: scala.collection.mutable.IndexedSeq[String] = null 40 | 41 | @BeanProperty 42 | var resizableArray: scala.collection.mutable.ResizableArray[String] = null 43 | 44 | @BeanProperty 45 | var linearSeq: scala.collection.LinearSeq[String] = null 46 | 47 | @BeanProperty 48 | var immutableLinearSeq: scala.collection.immutable.LinearSeq[String] = null 49 | 50 | @BeanProperty 51 | var mutableLinearSeq: scala.collection.mutable.LinearSeq[String] = null 52 | 53 | @BeanProperty 54 | var buffer: scala.collection.mutable.Buffer[String] = null 55 | 56 | @BeanProperty 57 | var set: scala.collection.Set[String] = null 58 | 59 | @BeanProperty 60 | var immutableSet: scala.collection.immutable.Set[String] = null 61 | 62 | @BeanProperty 63 | var mutableSet: scala.collection.mutable.Set[String] = null 64 | 65 | @BeanProperty 66 | var map: scala.collection.Map[String, String] = null 67 | 68 | @BeanProperty 69 | var immutableMap: scala.collection.immutable.Map[String, String] = null 70 | 71 | @BeanProperty 72 | var mutableMap: scala.collection.mutable.Map[String, String] = null 73 | 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/beans/propertyeditors/PrimitivesBean.scala: -------------------------------------------------------------------------------- 1 | package org.springframework.scala.beans.propertyeditors 2 | 3 | /* 4 | * Copyright 2011-2012 the original author or authors. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import scala.beans.BeanProperty 20 | 21 | /** 22 | * @author Arjen Poutsma 23 | */ 24 | class PrimitivesBean { 25 | 26 | @BeanProperty 27 | var byte: Byte = 0 28 | 29 | @BeanProperty 30 | var short: Short = 0 31 | 32 | @BeanProperty 33 | var int: Int = 0 34 | 35 | @BeanProperty 36 | var long: Long = 0 37 | 38 | @BeanProperty 39 | var char: Char = 0 40 | 41 | @BeanProperty 42 | var float: Float = 0F 43 | 44 | @BeanProperty 45 | var double: Double = 0D 46 | 47 | @BeanProperty 48 | var bool: Boolean = false 49 | 50 | @BeanProperty 51 | var string: String = "" 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/beans/propertyeditors/ScalaCollectionEditorTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.propertyeditors 18 | 19 | import org.scalatest.FunSuite 20 | import org.junit.runner.RunWith 21 | import org.scalatest.junit.JUnitRunner 22 | 23 | @RunWith(classOf[JUnitRunner]) 24 | class ScalaCollectionEditorTests extends FunSuite { 25 | 26 | test("null as empty collection") { 27 | val editor = new ScalaCollectionEditor(Seq.newBuilder[String] _, true) 28 | editor.setValue(null) 29 | val result = editor.getValue.asInstanceOf[Seq[String]] 30 | assert(result.isEmpty) 31 | } 32 | 33 | test("null not as empty collection") { 34 | val editor = new ScalaCollectionEditor(Seq.newBuilder[String] _, false) 35 | editor.setValue(null) 36 | val result = editor.getValue 37 | assert(result == null) 38 | } 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/beans/propertyeditors/ScalaEditorRegistrarTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.propertyeditors 18 | 19 | import org.scalatest.FunSuite 20 | import org.springframework.context.support.ClassPathXmlApplicationContext 21 | import org.junit.runner.RunWith 22 | import org.scalatest.junit.JUnitRunner 23 | 24 | /** 25 | * @author Arjen Poutsma 26 | */ 27 | @RunWith(classOf[JUnitRunner]) 28 | class ScalaEditorRegistrarTests extends FunSuite { 29 | 30 | val applicationContext = new ClassPathXmlApplicationContext("scalaEditorRegistrarTest.xml", getClass) 31 | 32 | test("primitives") { 33 | val bean = applicationContext.getBean("primitivesBean", classOf[PrimitivesBean]) 34 | assert(bean.byte == 42) 35 | assert(bean.short == 42) 36 | assert(bean.int == 42) 37 | assert(bean.long == 42) 38 | assert(bean.char == '4') 39 | assert(bean.float == 42) 40 | assert(bean.double == 42) 41 | assert(bean.bool) 42 | assert(bean.string == "foo") 43 | } 44 | 45 | test("types") { 46 | val bean = applicationContext.getBean("typesBean", classOf[TypesBean]) 47 | assert(bean.regex.toString() == "\\d") 48 | } 49 | 50 | test("collections") { 51 | val bean = applicationContext.getBean("collectionBean", classOf[CollectionsBean]) 52 | testSeq(bean.seq) 53 | testSeq(bean.immutableSeq) 54 | testSeq(bean.mutableSeq) 55 | 56 | testSeq(bean.indexedSeq) 57 | testSeq(bean.immutableIndexedSeq) 58 | testSeq(bean.mutableIndexedSeq) 59 | 60 | testSeq(bean.resizableArray) 61 | 62 | testSeq(bean.linearSeq) 63 | testSeq(bean.immutableLinearSeq) 64 | testSeq(bean.mutableLinearSeq) 65 | 66 | testSeq(bean.buffer) 67 | 68 | testSet(bean.set) 69 | testSet(bean.immutableSet) 70 | testSet(bean.mutableSet) 71 | 72 | testMap(bean.map) 73 | testMap(bean.immutableMap) 74 | testMap(bean.mutableMap) 75 | } 76 | 77 | private def testSeq(seq: Seq[String]) { 78 | assert(seq != null) 79 | assert(seq.size == 3) 80 | assert(seq.contains("one")) 81 | assert(seq.contains("two")) 82 | assert(seq.contains("three")) 83 | } 84 | 85 | private def testSet(set: scala.collection.Set[String]) { 86 | assert(set != null) 87 | assert(set.size == 3) 88 | assert(set.contains("one")) 89 | assert(set.contains("two")) 90 | assert(set.contains("three")) 91 | } 92 | 93 | private def testMap(map: scala.collection.Map[String, String]) { 94 | assert(map != null) 95 | assert(map.size == 1) 96 | assert(map.contains("foo")) 97 | assert(map("foo") == "bar") 98 | } 99 | 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/beans/propertyeditors/TypesBean.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.beans.propertyeditors 18 | 19 | import scala.beans.BeanProperty 20 | import scala.util.matching.Regex 21 | 22 | /** 23 | * @author Arjen Poutsma 24 | */ 25 | class TypesBean { 26 | 27 | @BeanProperty 28 | var regex: Regex = null 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/context/ApplicationListenerAdapterTest.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.context 18 | 19 | import org.junit.runner.RunWith 20 | import org.scalatest.junit.JUnitRunner 21 | import org.scalatest.{BeforeAndAfterEach, GivenWhenThen, FunSuite} 22 | import org.springframework.context.support.GenericApplicationContext 23 | import org.springframework.scala.context.function.FunctionalConfiguration 24 | import org.springframework.beans.factory.support.DefaultBeanNameGenerator 25 | import org.springframework.context.ApplicationEvent 26 | import scala.collection.mutable.ArrayBuffer 27 | import org.springframework.context.event.{ContextClosedEvent, ContextRefreshedEvent} 28 | 29 | /** 30 | * @author Tomasz Nurkiewicz 31 | */ 32 | @RunWith(classOf[JUnitRunner]) 33 | class ApplicationListenerAdapterTest extends FunSuite with GivenWhenThen with BeforeAndAfterEach { 34 | 35 | var applicationContext: GenericApplicationContext = _ 36 | 37 | val beanNameGenerator = new DefaultBeanNameGenerator() 38 | 39 | override def beforeEach() { 40 | super.beforeEach() 41 | applicationContext = new GenericApplicationContext() 42 | } 43 | 44 | test("should capture startup and shutdown events") { 45 | Given("context with catch-all listener") 46 | val config = new FunctionalConfiguration() { 47 | bean() { 48 | new AggregatingAllBean 49 | } 50 | } 51 | config.register(applicationContext, beanNameGenerator) 52 | val aggregator = applicationContext.getBean(classOf[AggregatingAllBean]) 53 | 54 | When("context started and destroyed") 55 | applicationContext.refresh() 56 | applicationContext.destroy() 57 | 58 | Then("two events captured") 59 | val classesOfEvents = aggregator.receivedEvents.map(_.getClass) 60 | assert(classesOfEvents === Seq(classOf[ContextRefreshedEvent], classOf[ContextClosedEvent])) 61 | } 62 | 63 | test("should only capture destroy event") { 64 | Given("context with listener listening for destroy event") 65 | val config = new FunctionalConfiguration() { 66 | bean() { 67 | new AggregatingDestroyBean 68 | } 69 | } 70 | config.register(applicationContext, beanNameGenerator) 71 | val aggregator = applicationContext.getBean(classOf[AggregatingDestroyBean]) 72 | 73 | When("context started and destroyed") 74 | applicationContext.refresh() 75 | applicationContext.destroy() 76 | 77 | Then("destroy event captured") 78 | val classesOfEvents = aggregator.receivedEvents.map(_.getClass) 79 | assert(classesOfEvents === Seq(classOf[ContextClosedEvent])) 80 | } 81 | 82 | test("should allow capturing custom events") { 83 | Given("context with listener listening for custom event") 84 | val config = new FunctionalConfiguration() { 85 | bean() { 86 | new AggregatingCustomEventsBean 87 | } 88 | } 89 | config.register(applicationContext, beanNameGenerator) 90 | val aggregator = applicationContext.getBean(classOf[AggregatingCustomEventsBean]) 91 | applicationContext.refresh() 92 | 93 | When("custom events sent") 94 | applicationContext.publishEvent(CustomEvent(42, enabled = true, this)) 95 | applicationContext.publishEvent(CustomEvent(43, enabled = true, this)) 96 | applicationContext.publishEvent(CustomEvent(44, enabled = true, this)) 97 | 98 | Then("all custom events sent and nothing else") 99 | assert(aggregator.receivedIds === Seq(42, 43, 44)) 100 | } 101 | 102 | test("should capture both built-in and custom events") { 103 | Given("context with catch-all listener") 104 | val config = new FunctionalConfiguration() { 105 | bean() { 106 | new AggregatingAllBean 107 | } 108 | } 109 | config.register(applicationContext, beanNameGenerator) 110 | val aggregator = applicationContext.getBean(classOf[AggregatingAllBean]) 111 | 112 | When("context started and destroyed + custom event") 113 | applicationContext.refresh() 114 | applicationContext.publishEvent(CustomEvent(42, enabled = false, this)) 115 | applicationContext.destroy() 116 | 117 | Then("both built-in and custom events captured") 118 | val classesOfEvents = aggregator.receivedEvents.map(_.getClass) 119 | assert(classesOfEvents === Seq(classOf[ContextRefreshedEvent], classOf[CustomEvent], classOf[ContextClosedEvent])) 120 | } 121 | 122 | test("should allow advanced pattern matching on custom events") { 123 | Given("context with listener listening for custom event") 124 | val config = new FunctionalConfiguration() { 125 | bean() { 126 | new AdvancedAggregatingCustomEventsBean 127 | } 128 | } 129 | config.register(applicationContext, beanNameGenerator) 130 | val aggregator = applicationContext.getBean(classOf[AdvancedAggregatingCustomEventsBean]) 131 | applicationContext.refresh() 132 | 133 | When("custom events sent") 134 | applicationContext.publishEvent(CustomEvent(42, enabled = false, this)) 135 | applicationContext.publishEvent(CustomEvent(42, enabled = true, this)) 136 | applicationContext.publishEvent(CustomEvent(43, enabled = false, this)) 137 | applicationContext.publishEvent(CustomEvent(44, enabled = true, this)) 138 | 139 | Then("only custom events matching pattern are captured") 140 | assert(aggregator.receivedIds === Seq(44)) 141 | } 142 | 143 | test("should allow registering multiple listeners") { 144 | Given("context with two different listeners") 145 | val config = new FunctionalConfiguration() { 146 | bean() { 147 | new AggregatingAllBean 148 | } 149 | bean() { 150 | new AggregatingCustomEventsBean 151 | } 152 | } 153 | config.register(applicationContext, beanNameGenerator) 154 | val allAggregator = applicationContext.getBean(classOf[AggregatingAllBean]) 155 | val customAggregator = applicationContext.getBean(classOf[AggregatingCustomEventsBean]) 156 | 157 | When("context started and destroyed") 158 | applicationContext.refresh() 159 | applicationContext.publishEvent(CustomEvent(47, enabled = true, this)) 160 | applicationContext.destroy() 161 | 162 | Then("both listeners reached") 163 | assert(allAggregator.receivedEvents.map(_.getClass) === Seq(classOf[ContextRefreshedEvent], classOf[CustomEvent], classOf[ContextClosedEvent])) 164 | assert(customAggregator.receivedIds === Seq(47)) 165 | } 166 | 167 | } 168 | 169 | class AggregatingAllBean extends ApplicationListenerAdapter { 170 | val receivedEvents = new ArrayBuffer[ApplicationEvent]() 171 | def onEvent = { 172 | case x => receivedEvents += x 173 | } 174 | } 175 | 176 | class AggregatingDestroyBean extends ApplicationListenerAdapter { 177 | val receivedEvents = new ArrayBuffer[ApplicationEvent]() 178 | def onEvent = { 179 | case closed: ContextClosedEvent => receivedEvents += closed 180 | } 181 | } 182 | 183 | class AggregatingCustomEventsBean extends ApplicationListenerAdapter { 184 | val receivedIds = new ArrayBuffer[Int]() 185 | def onEvent = { 186 | case CustomEvent(id, _, _) => receivedIds += id 187 | } 188 | } 189 | 190 | case class CustomEvent(id: Int, enabled: Boolean, eventSource: AnyRef) extends ApplicationEvent(eventSource) 191 | 192 | class AdvancedAggregatingCustomEventsBean extends ApplicationListenerAdapter { 193 | val receivedIds = new ArrayBuffer[Int]() 194 | def onEvent = { 195 | case CustomEvent(id, true, _) if id > 42 => receivedIds += id 196 | } 197 | } 198 | 199 | 200 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/context/function/ComponentScanTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.context.function 18 | 19 | import org.junit.runner.RunWith 20 | import org.scalatest.junit.JUnitRunner 21 | import org.scalatest.{Matchers, GivenWhenThen, FunSuite} 22 | import org.scalatest.matchers.ShouldMatchers 23 | import org.springframework.stereotype.Component 24 | import org.springframework.context.annotation.{AnnotationScopeMetadataResolver, ScopedProxyMode} 25 | import org.springframework.core.`type`.filter.RegexPatternTypeFilter 26 | import java.util.regex.Pattern 27 | import org.springframework.beans.factory.NoSuchBeanDefinitionException 28 | 29 | @RunWith(classOf[JUnitRunner]) 30 | class ComponentScanTests extends FunSuite with Matchers with GivenWhenThen { 31 | 32 | // Fixtures 33 | 34 | var context : FunctionalConfigApplicationContext = _ 35 | 36 | // Tests 37 | 38 | test("should load components with var arg componentScan") { 39 | Given("loaded config") 40 | context = FunctionalConfigApplicationContext[VarArgComponentScanConfig] 41 | 42 | When("scanned component is retrieved") 43 | val scannedComponent = context.getBean(classOf[TestComponent]) 44 | 45 | Then("component should not be null") 46 | scannedComponent should not be (null) 47 | } 48 | 49 | test("should load components with basic componentScan") { 50 | Given("loaded config") 51 | context = FunctionalConfigApplicationContext[BasicComponentScanConfig] 52 | 53 | When("scanned component is retrieved") 54 | val scannedComponent = context.getBean(classOf[TestComponent]) 55 | 56 | Then("component should not be null") 57 | scannedComponent should not be (null) 58 | } 59 | 60 | test("should validate conflicting scope configuration") { 61 | When("loaded config") 62 | an [IllegalArgumentException] should be thrownBy { 63 | FunctionalConfigApplicationContext[ScopeConflictComponentScanConfig] 64 | } 65 | } 66 | 67 | test("should exclude from scan") { 68 | Given("loaded config") 69 | context = FunctionalConfigApplicationContext[ExcludingComponentScanConfig] 70 | 71 | When("scanned component is retrieved") 72 | an [NoSuchBeanDefinitionException] should be thrownBy { 73 | context.getBean(classOf[TestComponent]) 74 | } 75 | } 76 | 77 | test("should include in scan") { 78 | Given("loaded config") 79 | context = FunctionalConfigApplicationContext[IncludingComponentScanConfig] 80 | 81 | When("scanned component is retrieved") 82 | val scannedComponent = context.getBean(classOf[TestComponent]) 83 | 84 | Then("component should not be null") 85 | scannedComponent should not be null 86 | } 87 | 88 | } 89 | 90 | // Configuration classes 91 | 92 | class BasicComponentScanConfig extends FunctionalConfiguration with ContextSupport { 93 | 94 | componentScan(basePackages = Seq("org.springframework.scala.context.function")) 95 | 96 | } 97 | 98 | class VarArgComponentScanConfig extends FunctionalConfiguration with ContextSupport { 99 | 100 | componentScan("org.springframework.scala.context.function") 101 | 102 | } 103 | 104 | class ScopeConflictComponentScanConfig extends FunctionalConfiguration with ContextSupport { 105 | 106 | componentScan(basePackages = Seq("org.springframework.scala.context.function"), 107 | scopedProxy = Some(ScopedProxyMode.TARGET_CLASS), scopeResolver = Some(new AnnotationScopeMetadataResolver)) 108 | 109 | } 110 | 111 | class ExcludingComponentScanConfig extends FunctionalConfiguration with ContextSupport { 112 | 113 | componentScan(basePackages = Seq("org.springframework.scala.context.function"), 114 | excludeFilters = Seq(new RegexPatternTypeFilter(Pattern.compile(".*Component")))) 115 | 116 | } 117 | 118 | class IncludingComponentScanConfig extends FunctionalConfiguration with ContextSupport { 119 | 120 | componentScan(basePackages = Seq("org.springframework.scala.context.function"), 121 | includeFilters = Seq(new RegexPatternTypeFilter(Pattern.compile(".*Component")))) 122 | 123 | } 124 | 125 | // Test component 126 | 127 | @Component 128 | class TestComponent { 129 | } -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/context/function/ContextSupportTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.context.function 18 | 19 | import org.springframework.context.support.GenericApplicationContext 20 | import org.springframework.beans.factory.support.DefaultBeanNameGenerator 21 | import org.junit.runner.RunWith 22 | import org.scalatest.junit.JUnitRunner 23 | import org.scalatest.{BeforeAndAfterEach, FunSuite} 24 | import org.springframework.beans.factory.annotation.Autowired 25 | 26 | @RunWith(classOf[JUnitRunner]) 27 | class ContextSupportTests extends FunSuite with BeforeAndAfterEach { 28 | 29 | var applicationContext: GenericApplicationContext = _ 30 | 31 | val beanNameGenerator = new DefaultBeanNameGenerator() 32 | 33 | override protected def beforeEach() { 34 | applicationContext = new GenericApplicationContext() 35 | } 36 | 37 | test("enableAnnotationConfig()") { 38 | val config = new FunctionalConfiguration with ContextSupport { 39 | 40 | enableAnnotationConfig() 41 | 42 | bean("a") { new A } 43 | 44 | bean("b") { new B } 45 | 46 | } 47 | 48 | config.register(applicationContext, beanNameGenerator) 49 | 50 | applicationContext.refresh() 51 | 52 | val b = applicationContext.getBean("b", classOf[B]) 53 | assert(b.a != null) 54 | } 55 | 56 | } 57 | 58 | class A 59 | 60 | class B { 61 | @Autowired 62 | var a: A = _ 63 | } -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/context/function/FunctionalConfigApplicationContextTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.context.function 18 | 19 | import org.scalatest.FunSuite 20 | import org.junit.runner.RunWith 21 | import org.scalatest.junit.JUnitRunner 22 | 23 | /** 24 | * @author Arjen Poutsma 25 | */ 26 | @RunWith(classOf[JUnitRunner]) 27 | class FunctionalConfigApplicationContextTests extends FunSuite { 28 | 29 | test("registerClass") { 30 | val appContext = new FunctionalConfigApplicationContext() 31 | appContext.registerClass[MyFunctionalConfiguration] 32 | val foo = appContext.getBean("foo") 33 | assert("Foo" == foo) 34 | } 35 | 36 | test("registerClasses") { 37 | val appContext = new FunctionalConfigApplicationContext() 38 | appContext.registerClasses(classOf[MyFunctionalConfiguration]) 39 | val foo = appContext.getBean("foo") 40 | assert("Foo" == foo) 41 | } 42 | 43 | test("registerConfigurations") { 44 | val appContext = new FunctionalConfigApplicationContext() 45 | appContext.registerConfigurations(new MyFunctionalConfiguration) 46 | val foo = appContext.getBean("foo") 47 | assert("Foo" == foo) 48 | } 49 | 50 | test("companion single class") { 51 | val appContext = FunctionalConfigApplicationContext[MyFunctionalConfiguration] 52 | val foo = appContext.getBean("foo") 53 | assert("Foo" == foo) 54 | } 55 | 56 | test("companion multiple classes") { 57 | val appContext = FunctionalConfigApplicationContext(classOf[MyFunctionalConfiguration]) 58 | val foo = appContext.getBean("foo") 59 | assert("Foo" == foo) 60 | } 61 | 62 | test("context[Class]") { 63 | val appContext = FunctionalConfigApplicationContext(classOf[MyFunctionalConfiguration]) 64 | val foo = appContext[String] 65 | assert("Foo" == foo) 66 | } 67 | 68 | test("context[Class]('beanName')") { 69 | val appContext = FunctionalConfigApplicationContext(classOf[MyFunctionalConfiguration]) 70 | val foo = appContext[String]("foo") 71 | assert("Foo" == foo) 72 | } 73 | test("context.beansOfType[String] call without empty parameter list") { 74 | val appContext = FunctionalConfigApplicationContext(classOf[MyFunctionalConfiguration]) 75 | val foos : Map[String,String] = appContext.beansOfType[String] 76 | assert(1 === foos.size) 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/context/function/FunctionalConfigurationTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.context.function 18 | 19 | import org.springframework.beans.factory.config.BeanDefinition 20 | import org.springframework.context.support.GenericApplicationContext 21 | import org.scalatest.{BeforeAndAfterEach, FunSuite} 22 | import org.springframework.beans.factory.support.DefaultBeanNameGenerator 23 | import org.junit.runner.RunWith 24 | import org.scalatest.junit.JUnitRunner 25 | import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor 26 | 27 | /** 28 | * @author Arjen Poutsma 29 | */ 30 | @RunWith(classOf[JUnitRunner]) 31 | class FunctionalConfigurationTests extends FunSuite with BeforeAndAfterEach { 32 | 33 | var applicationContext: GenericApplicationContext = _ 34 | 35 | val beanNameGenerator = new DefaultBeanNameGenerator() 36 | 37 | override protected def beforeEach() { 38 | applicationContext = new GenericApplicationContext() 39 | } 40 | 41 | test("getBean()") { 42 | val config = new FunctionalConfiguration { 43 | bean("foo") { 44 | "Foo" 45 | } 46 | } 47 | config.register(applicationContext, beanNameGenerator) 48 | 49 | val foo = config.getBean[String]("foo") 50 | assert("Foo" === foo) 51 | } 52 | 53 | test("bean() aliases") { 54 | val config = new FunctionalConfiguration { 55 | 56 | bean(name = "foo", aliases = Seq("bar")) { 57 | "Foo" 58 | } 59 | } 60 | config.register(applicationContext, beanNameGenerator) 61 | 62 | val foo = applicationContext.getBean("foo", classOf[String]) 63 | val bar = applicationContext.getBean("bar", classOf[String]) 64 | 65 | assert(foo eq bar) 66 | } 67 | 68 | test("singleton()") { 69 | var count = 0 70 | 71 | val config = new FunctionalConfiguration { 72 | 73 | val foo = singleton("foo") { 74 | count += 1 75 | new Person("John", "Doe") 76 | } 77 | } 78 | 79 | config.register(applicationContext, beanNameGenerator) 80 | 81 | val beanFromConfig: Person = config.foo() 82 | val beanFromBeanFactory = applicationContext.getBean("foo", classOf[Person]) 83 | assert(beanFromConfig eq beanFromBeanFactory) 84 | assert(1 == count) 85 | } 86 | 87 | test("prototype()") { 88 | var count = 0 89 | 90 | val config = new FunctionalConfiguration { 91 | 92 | val foo = prototype("foo") { 93 | count += 1 94 | new Person("John", "Doe") 95 | } 96 | } 97 | 98 | config.register(applicationContext, beanNameGenerator) 99 | 100 | val beanFromConfig1 = config.foo() 101 | val beanFromConfig2 = config.foo() 102 | val beanFromBeanFactory = applicationContext.getBean("foo", classOf[Person]) 103 | assert(!(beanFromConfig1 eq beanFromConfig2)) 104 | assert(!(beanFromConfig1 eq beanFromBeanFactory)) 105 | assert(!(beanFromConfig2 eq beanFromBeanFactory)) 106 | assert(3 == count) 107 | } 108 | 109 | test("singleton bean()") { 110 | var count = 0 111 | 112 | val config = new FunctionalConfiguration { 113 | 114 | val foo = bean("foo") { 115 | count += 1 116 | new Person("John", "Doe") 117 | } 118 | } 119 | config.register(applicationContext, beanNameGenerator) 120 | 121 | val beanFromConfig1 = config.foo() 122 | val beanFromConfig2 = config.foo() 123 | val beanFromBeanFactory = applicationContext.getBean("foo", classOf[Person]) 124 | assert(beanFromConfig1 eq beanFromConfig2) 125 | assert(beanFromConfig1 eq beanFromBeanFactory) 126 | assert(1 == count) 127 | } 128 | 129 | test("prototype bean()") { 130 | var count = 0 131 | 132 | val config = new FunctionalConfiguration { 133 | 134 | val foo = bean("foo", scope = BeanDefinition.SCOPE_PROTOTYPE) { 135 | count += 1 136 | new Person("John", "Doe") 137 | } 138 | } 139 | 140 | config.register(applicationContext, beanNameGenerator) 141 | 142 | val beanFromConfig1 = config.foo() 143 | val beanFromConfig2 = config.foo() 144 | val beanFromBeanFactory = applicationContext.getBean("foo", classOf[Person]) 145 | assert(!(beanFromConfig1 eq beanFromConfig2)) 146 | assert(!(beanFromConfig1 eq beanFromBeanFactory)) 147 | assert(!(beanFromConfig2 eq beanFromBeanFactory)) 148 | assert(3 == count) 149 | } 150 | 151 | test("references") { 152 | val config = new FunctionalConfiguration() { 153 | val jack = bean() { 154 | new Person("Jack", "Doe") 155 | } 156 | 157 | val jane = bean() { 158 | new Person("Jane", "Doe") 159 | } 160 | 161 | val john = bean() { 162 | val person = new Person("John", "Doe") 163 | person.father = jack() 164 | person.mother = jane() 165 | person 166 | } 167 | } 168 | config.register(applicationContext, beanNameGenerator) 169 | 170 | val john = config.john() 171 | assert(john.father eq config.jack()) 172 | assert(john.mother eq config.jane()) 173 | } 174 | 175 | test("composition through mixin") { 176 | trait FirstNameConfig extends FunctionalConfiguration { 177 | 178 | lazy val firstName = bean() { 179 | "John" 180 | } 181 | } 182 | trait LastNameConfig extends FunctionalConfiguration { 183 | 184 | lazy val lastName = bean() { 185 | "Doe" 186 | } 187 | } 188 | val config = new FirstNameConfig with LastNameConfig { 189 | val john = bean() { 190 | new Person(firstName(), lastName()) 191 | } 192 | } 193 | config.register(applicationContext, beanNameGenerator) 194 | 195 | val john = config.john() 196 | assert("John" == john.firstName) 197 | assert("Doe" == john.lastName) 198 | } 199 | 200 | test("composition through inheritance") { 201 | class FirstNameConfig extends FunctionalConfiguration { 202 | 203 | val firstName = bean() { 204 | "John" 205 | } 206 | } 207 | class LastNameConfig extends FirstNameConfig { 208 | 209 | val lastName = bean() { 210 | "Doe" 211 | } 212 | } 213 | class Config extends LastNameConfig { 214 | 215 | val john = bean() { 216 | new Person(firstName(), lastName()) 217 | } 218 | } 219 | val config = new Config 220 | config.register(applicationContext, beanNameGenerator) 221 | 222 | val john = config.john() 223 | assert("John" == john.firstName) 224 | assert("Doe" == john.lastName) 225 | } 226 | 227 | test("init and destroy") { 228 | val applicationContext = new GenericApplicationContext() 229 | 230 | val config = new FunctionalConfiguration { 231 | 232 | val foo = bean("foo") { 233 | new InitializablePerson("John", "Doe") 234 | } init { 235 | _.initialize() 236 | } destroy { 237 | _.destroy() 238 | } 239 | } 240 | config.register(applicationContext, beanNameGenerator) 241 | applicationContext.refresh() 242 | 243 | val foo = applicationContext.getBean("foo", classOf[InitializablePerson]) 244 | assert(foo.initialised) 245 | applicationContext.close() 246 | assert(!foo.initialised) 247 | } 248 | 249 | test("profile") { 250 | applicationContext.getEnvironment.addActiveProfile("profile1") 251 | 252 | val config = new FunctionalConfiguration() { 253 | 254 | profile("profile1") { 255 | bean("foo") { 256 | "Foo" 257 | } 258 | } 259 | 260 | profile("profile2") { 261 | bean("bar") { 262 | "Bar" 263 | } 264 | } 265 | } 266 | config.register(applicationContext, beanNameGenerator) 267 | 268 | assert(applicationContext.containsBean("foo")) 269 | assert(!applicationContext.containsBean("bar")) 270 | assert("Foo" == applicationContext.getBean("foo")) 271 | } 272 | 273 | test("importXml") { 274 | val config = new FunctionalConfiguration() { 275 | 276 | importXml( 277 | "classpath:/org/springframework/scala/context/function/imported.xml") 278 | 279 | val john = bean() { 280 | new Person(getBean[String]("firstName"), getBean[String]("lastName")) 281 | } 282 | } 283 | config.register(applicationContext, beanNameGenerator) 284 | assert("John" == config.john().firstName) 285 | assert("Doe" == config.john().lastName) 286 | } 287 | 288 | test("importClass") { 289 | val config = new FunctionalConfiguration() { 290 | 291 | importClass(classOf[MyAnnotatedConfiguration]) 292 | 293 | val john = bean() { 294 | new Person(getBean[String]("firstName"), getBean[String]("lastName")) 295 | } 296 | } 297 | config.register(applicationContext, beanNameGenerator) 298 | applicationContext.refresh() 299 | 300 | assert("John" == config.john().firstName) 301 | assert("Doe" == config.john().lastName) 302 | } 303 | 304 | test("importClass via tag") { 305 | val config = new FunctionalConfiguration() { 306 | 307 | importClass[MyAnnotatedConfiguration]() 308 | 309 | val john = bean() { 310 | new Person(getBean[String]("firstName"), getBean[String]("lastName")) 311 | } 312 | } 313 | config.register(applicationContext, beanNameGenerator) 314 | applicationContext.refresh() 315 | 316 | assert("John" == config.john().firstName) 317 | assert("Doe" == config.john().lastName) 318 | } 319 | 320 | test("beanPostProcessor") { 321 | val config = new FunctionalConfiguration { 322 | 323 | bean("john") { 324 | new AutowirePerson("John", "Doe") 325 | } 326 | 327 | bean("jane") { 328 | new Person("Jane", "Roe") 329 | } 330 | 331 | bean() { new AutowiredAnnotationBeanPostProcessor} 332 | 333 | } 334 | 335 | config.register(applicationContext, beanNameGenerator) 336 | applicationContext.refresh() 337 | 338 | val jane= applicationContext.getBean("jane", classOf[Person]) 339 | val john = applicationContext.getBean("john", classOf[AutowirePerson]) 340 | 341 | assert(jane === john.friend) 342 | } 343 | 344 | } 345 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/context/function/MyFunctionalConfiguration.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.context.function 18 | 19 | class MyFunctionalConfiguration extends FunctionalConfiguration { 20 | 21 | bean("foo") { 22 | "Foo" 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/context/function/Person.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.context.function 18 | 19 | import org.springframework.beans.factory.annotation.Autowired 20 | 21 | class Person(val firstName: String, val lastName: String) { 22 | 23 | var father: Person = _ 24 | var mother: Person = _ 25 | 26 | override def toString = firstName + " " + lastName 27 | } 28 | 29 | class InitializablePerson(firstName: String, lastName: String) 30 | extends Person(firstName, lastName) { 31 | 32 | var initialised = false 33 | 34 | def initialize() { 35 | initialised = true 36 | } 37 | 38 | def destroy() { 39 | initialised = false 40 | } 41 | } 42 | 43 | class AutowirePerson(firstName: String, lastName: String) 44 | extends Person(firstName, lastName) { 45 | 46 | @Autowired 47 | var friend: Person = _ 48 | 49 | } -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/test/context/FunctionalConfigurationsTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.test.context 18 | 19 | import org.springframework.test.context.ContextConfiguration 20 | import org.junit.Test 21 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner 22 | import org.junit.runner.RunWith 23 | import org.springframework.beans.factory.annotation.Autowired 24 | import org.springframework.scala.context.function.FunctionalConfiguration 25 | import java.util.Date 26 | 27 | @RunWith(classOf[SpringJUnit4ClassRunner]) 28 | @ContextConfiguration(loader = classOf[FunctionalConfigContextLoader]) 29 | @FunctionalConfigurations(classOf[TestConfig], classOf[AnotherTestConfig]) 30 | class FunctionalConfigurationsTests { 31 | 32 | @Autowired 33 | var stringBean : String = _ 34 | 35 | @Autowired 36 | var dateBean : Date = _ 37 | 38 | @Test 39 | def shouldInjectStringBean() { 40 | assert(stringBean == "stringBean") 41 | } 42 | 43 | @Test 44 | def shouldInjectDateBean() { 45 | assert(dateBean != null) 46 | } 47 | 48 | } 49 | 50 | class TestConfig extends FunctionalConfiguration { 51 | 52 | bean("stringBean")("stringBean") 53 | 54 | } 55 | 56 | class AnotherTestConfig extends FunctionalConfiguration { 57 | 58 | bean("dateBean")(new Date) 59 | 60 | } -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/test/context/ProfiledFunctionalConfigurationsTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.test.context 18 | 19 | import org.springframework.test.context.{ActiveProfiles, ContextConfiguration} 20 | import org.junit.Test 21 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner 22 | import org.junit.runner.RunWith 23 | import org.springframework.beans.factory.annotation.Autowired 24 | import org.springframework.scala.context.function.FunctionalConfiguration 25 | import java.util.Date 26 | 27 | @RunWith(classOf[SpringJUnit4ClassRunner]) 28 | @ContextConfiguration(loader = classOf[FunctionalConfigContextLoader]) 29 | @FunctionalConfigurations(classOf[ProfiledTestConfig]) 30 | @ActiveProfiles(Array("activeProfile")) 31 | class ProfiledFunctionalConfigurationsTests { 32 | 33 | @Autowired 34 | var stringBean: String = _ 35 | 36 | @Autowired(required = false) 37 | var dateBean: Date = _ 38 | 39 | @Test 40 | def shouldInjectBeanFromActiveProfile() { 41 | assert("stringBean" == stringBean) 42 | } 43 | 44 | @Test 45 | def shouldNotInjectBeanFromInactiveProfile() { 46 | assert(null == dateBean) 47 | } 48 | 49 | } 50 | 51 | class ProfiledTestConfig extends FunctionalConfiguration { 52 | 53 | profile("activeProfile") { 54 | bean("stringBean")("stringBean") 55 | } 56 | 57 | profile("inactiveProfile") { 58 | bean("dateBean")(new Date) 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/transaction/function/TransactionSupportTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.transaction.function 18 | 19 | import org.junit.runner.RunWith 20 | import org.scalatest.junit.JUnitRunner 21 | import org.scalatest.{BeforeAndAfterEach, FunSuite} 22 | import org.springframework.transaction.support.{DefaultTransactionStatus, AbstractPlatformTransactionManager, TransactionSynchronizationManager} 23 | import org.springframework.transaction.annotation.Transactional 24 | import org.springframework.transaction.TransactionDefinition 25 | import org.springframework.aop.config.AopConfigUtils 26 | import org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator 27 | import org.springframework.transaction.config.TransactionManagementConfigUtils 28 | import org.springframework.scala.context.function.{FunctionalConfigApplicationContext, FunctionalConfiguration} 29 | 30 | /** 31 | * @author Maciej Zientarski 32 | */ 33 | @RunWith(classOf[JUnitRunner]) 34 | class TransactionSupportTests extends FunSuite with BeforeAndAfterEach { 35 | var applicationContext: FunctionalConfigApplicationContext = _ 36 | 37 | override protected def beforeEach() { 38 | applicationContext = new FunctionalConfigApplicationContext() 39 | } 40 | 41 | test("enableTransactionManagement() default values") { 42 | //given 43 | val config = new FunctionalConfiguration with TransactionSupport { 44 | 45 | enableTransactionManagement() 46 | 47 | bean(TransactionSupport.DEFAULT_TRANSACTION_MANAGER_NAME) { 48 | new DummyTransactionManager 49 | } 50 | } 51 | 52 | applicationContext.registerConfigurations(config) 53 | 54 | //then 55 | val infrastructureAdvisorAutoProxyCreator = applicationContext.getBean( 56 | AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME, 57 | classOf[InfrastructureAdvisorAutoProxyCreator] 58 | ) 59 | assert(!infrastructureAdvisorAutoProxyCreator.isProxyTargetClass) 60 | 61 | assert(!applicationContext.containsBean( 62 | TransactionManagementConfigUtils.TRANSACTION_ASPECT_BEAN_NAME)) 63 | } 64 | 65 | test("enableTransactionManagement() makes @Transactional methods run in transaction") { 66 | //given 67 | val config = new FunctionalConfiguration with TransactionSupport { 68 | 69 | enableTransactionManagement() 70 | 71 | bean("frog") { 72 | new Frog 73 | } 74 | bean(TransactionSupport.DEFAULT_TRANSACTION_MANAGER_NAME) { 75 | new DummyTransactionManager 76 | } 77 | } 78 | 79 | applicationContext.registerConfigurations(config) 80 | applicationContext.refresh() 81 | 82 | //when 83 | val frog = applicationContext.getBean("frog", classOf[Frog]) 84 | 85 | //then 86 | assert(frog.hasTransaction === true) 87 | } 88 | 89 | test("enableTransactionManagement() with custom transaction manager name") { 90 | val config = new FunctionalConfiguration with TransactionSupport { 91 | val transactionManagerName = "myCustomTransactionManagerName" 92 | 93 | enableTransactionManagement(transactionManagerName = transactionManagerName) 94 | 95 | bean("frog") { 96 | new Frog 97 | } 98 | bean(transactionManagerName) { 99 | new DummyTransactionManager 100 | } 101 | } 102 | 103 | applicationContext.registerConfigurations(config) 104 | applicationContext.refresh() 105 | 106 | val frog = applicationContext.getBean("frog", classOf[Frog]) 107 | assert(frog.hasTransaction === true) 108 | } 109 | 110 | test("enableTransactionManagement() CGLIB proxy") { 111 | val config = new FunctionalConfiguration with TransactionSupport { 112 | 113 | enableTransactionManagement(ProxyTransactionMode(proxyTargetClass = true)) 114 | 115 | bean(TransactionSupport.DEFAULT_TRANSACTION_MANAGER_NAME) { 116 | new DummyTransactionManager 117 | } 118 | } 119 | 120 | applicationContext.registerConfigurations(config) 121 | applicationContext.refresh() 122 | 123 | val infrastructureAdvisorAutoProxyCreator = applicationContext.getBean( 124 | AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME, 125 | classOf[InfrastructureAdvisorAutoProxyCreator] 126 | ) 127 | assert(infrastructureAdvisorAutoProxyCreator.isProxyTargetClass) 128 | } 129 | 130 | test("enableTransactionManagement() AspectJ mode") { 131 | val config = new FunctionalConfiguration with TransactionSupport { 132 | 133 | enableTransactionManagement(AspectJTransactionMode()) 134 | 135 | bean(TransactionSupport.DEFAULT_TRANSACTION_MANAGER_NAME) { 136 | new DummyTransactionManager 137 | } 138 | } 139 | 140 | applicationContext.registerConfigurations(config) 141 | applicationContext.refresh() 142 | 143 | assert(applicationContext.containsBean( 144 | TransactionManagementConfigUtils.TRANSACTION_ASPECT_BEAN_NAME)) 145 | } 146 | } 147 | 148 | class DummyTransactionManager extends AbstractPlatformTransactionManager { 149 | def doGetTransaction(): AnyRef = { 150 | Unit 151 | } 152 | 153 | def doBegin(transaction: Any, definition: TransactionDefinition) {} 154 | 155 | def doCommit(status: DefaultTransactionStatus) {} 156 | 157 | def doRollback(status: DefaultTransactionStatus) {} 158 | } 159 | 160 | class Frog { 161 | @Transactional 162 | def hasTransaction: Boolean = { 163 | TransactionSynchronizationManager.isActualTransactionActive 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/transaction/support/TransactionManagementTests.scala: -------------------------------------------------------------------------------- 1 | package org.springframework.scala.transaction.support 2 | 3 | /* 4 | * Copyright 2002-2011 the original author or authors. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import org.springframework.transaction.annotation.{Isolation, Propagation} 20 | import org.scalatest.FunSuite 21 | import org.springframework.jdbc.datasource.DataSourceTransactionManager 22 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder 23 | import org.junit.runner.RunWith 24 | import org.scalatest.junit.JUnitRunner 25 | import org.springframework.jdbc.core.JdbcTemplate 26 | 27 | @RunWith(classOf[JUnitRunner]) 28 | class TransactionManagementTests extends FunSuite with TransactionManagement { 29 | 30 | private val db = new EmbeddedDatabaseBuilder().addDefaultScripts().build() 31 | 32 | private val template = new JdbcTemplate(db) 33 | 34 | val transactionManager = new DataSourceTransactionManager(db) 35 | 36 | test("default") { 37 | transactional() { 38 | status => { 39 | template.update("INSERT INTO USERS(ID, FIRST_NAME, LAST_NAME) VALUES (:id, :first_name, :last_name)", 3.asInstanceOf[Integer], "John", "Johnson") 40 | } 41 | } 42 | assertResult(1) { 43 | template.queryForObject("SELECT COUNT(ID) FROM USERS WHERE ID = 3", classOf[Integer]) 44 | } 45 | } 46 | 47 | test("custom parameters") { 48 | transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.REPEATABLE_READ) { 49 | status => { 50 | template.update("INSERT INTO USERS(ID, FIRST_NAME, LAST_NAME) VALUES (:id, :first_name, :last_name)", 4.asInstanceOf[Integer], "John", "Johnson") 51 | } 52 | } 53 | assertResult(1) { 54 | template.queryForObject("SELECT COUNT(ID) FROM USERS WHERE ID = 4", classOf[Integer]) 55 | } 56 | 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /src/test/scala/org/springframework/scala/transaction/support/TransactionSynchronizationManagerTests.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.scala.transaction.support 18 | 19 | import org.scalatest.{Matchers, FunSuite} 20 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder 21 | import org.springframework.jdbc.datasource.DataSourceTransactionManager 22 | import org.junit.runner.RunWith 23 | import org.scalatest.junit.JUnitRunner 24 | import collection.mutable.ListBuffer 25 | import org.scalatest.matchers.ShouldMatchers 26 | import org.springframework.transaction.support.TransactionSynchronization 27 | 28 | @RunWith(classOf[JUnitRunner]) 29 | class TransactionSynchronizationManagerTests extends FunSuite with Matchers with TransactionManagement { 30 | 31 | private val db = new EmbeddedDatabaseBuilder().addDefaultScripts().build() 32 | 33 | val transactionManager = new DataSourceTransactionManager(db) 34 | 35 | test("Should match single event.") { 36 | var completionStatus = -1 37 | transactional() { 38 | status => { 39 | TransactionSynchronizationManager.registerSynchronization { 40 | case AfterCompletionEvent(eventStatus) => completionStatus = eventStatus 41 | } 42 | } 43 | } 44 | assert(completionStatus === TransactionSynchronization.STATUS_COMMITTED) 45 | } 46 | 47 | test("Should match multiple events.") { 48 | var beforeEventReceived: Boolean = false 49 | var afterEventReceived: Boolean = false 50 | transactional() { 51 | status => { 52 | TransactionSynchronizationManager.registerSynchronization { 53 | case _: BeforeCommitEvent => beforeEventReceived = true 54 | case AfterCommitEvent => afterEventReceived = true 55 | } 56 | } 57 | } 58 | beforeEventReceived should be (true) 59 | afterEventReceived should be (true) 60 | } 61 | 62 | test("Should match all succeeded callbacks.") { 63 | val events = new ListBuffer[SynchronizationEvent] 64 | transactional() { 65 | status => { 66 | TransactionSynchronizationManager.registerSynchronization { 67 | case e: SynchronizationEvent => events += e 68 | } 69 | } 70 | } 71 | assert(events(0) === BeforeCommitEvent(readOnly = false)) 72 | assert(events(1) === BeforeCompletionEvent) 73 | assert(events(2) === AfterCommitEvent) 74 | assert(events(3) === AfterCompletionEvent(TransactionSynchronization.STATUS_COMMITTED)) 75 | } 76 | 77 | test("Should match all rollback callbacks.") { 78 | val events = new ListBuffer[SynchronizationEvent] 79 | transactional() { 80 | status => { 81 | TransactionSynchronizationManager.registerSynchronization { 82 | case e: SynchronizationEvent => events += e 83 | } 84 | status.setRollbackOnly() 85 | } 86 | } 87 | assert(events(0) === BeforeCompletionEvent) 88 | assert(events(1) === AfterCompletionEvent(TransactionSynchronization.STATUS_ROLLED_BACK)) 89 | } 90 | 91 | } 92 | --------------------------------------------------------------------------------