├── .gitignore ├── Kotlin_Examples.iml ├── README.adoc ├── build.gradle.kts ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src └── main ├── java └── de │ └── swirtz │ └── java │ └── RuntimeTypeAdapterFactory.java ├── kotlin ├── TopKtSOParser.kt └── de │ └── swirtz │ └── kotlin │ ├── conventions │ └── Fraction.kt │ ├── coroutines │ ├── ActorExample.kt │ ├── AsyncAwaitFun.kt │ ├── CancelCoroutine.kt │ ├── CancellationExample.kt │ ├── CoroutineFun.kt │ ├── CoroutineScopingExample.kt │ ├── CoroutineSingleThreaded.kt │ ├── EmailExample.kt │ ├── MutableStateAtomic.kt │ ├── MutableStateConfinement.kt │ └── ObserveContinuation.kt │ ├── delegation │ ├── DelegatedLazyMutable.kt │ ├── DelegatedThisContext.kt │ └── PropertyDelegation.kt │ ├── dsl │ ├── CsvToSql.kt │ └── DSL.kt │ ├── generics │ └── ClassWithTypeParam.kt │ ├── inheritance │ ├── Animal.kt │ ├── Cat.kt │ ├── ExampleInterface.kt │ └── sealed │ │ └── SealedMammal.kt │ ├── inline │ ├── InlineClassBoxingExample.kt │ ├── InlineClassSubtypeExample.kt │ └── InlineClassTypingExample.kt │ ├── lambda │ ├── ApplyExample.kt │ ├── LambdaFun.kt │ └── LambdaWithReceiver.kt │ ├── misc │ ├── ChecksAndCasts.kt │ ├── CollectionFun.kt │ ├── DataClasses.kt │ ├── GroupingFun.kt │ ├── HtmlBuilder.kt │ ├── LoopingFun.kt │ ├── MarkdownAnalyzer.kt │ ├── NullSafety.kt │ ├── StringsAndRegexFun.kt │ └── WhenExpressionFun.kt │ └── scoping │ ├── HttpExample.kt │ ├── ScopeHttpExample.kt │ ├── ScopePresentationAlso.kt │ ├── ScopePresentationApply.kt │ ├── ScopePresentationLet.kt │ ├── ScopePresentationRun.kt │ └── ScopePresentationWith.kt └── resources └── test.txt /.gitignore: -------------------------------------------------------------------------------- 1 | lib 2 | .gradle 3 | out 4 | target 5 | build 6 | .vertx 7 | .iws 8 | workplace.xml 9 | tasks.xml 10 | .idea 11 | **.iml 12 | .iws 13 | **SoTests.kt 14 | miscarat 15 | -------------------------------------------------------------------------------- /Kotlin_Examples.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | == Demo of Kotlin language features 2 | 3 | This repository contains simple samples of various *Kotlin* features. 4 | 5 | 6 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | import org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper 3 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 4 | 5 | val kotlinVersion = plugins.getPlugin(KotlinPluginWrapper::class.java).kotlinPluginVersion 6 | val kotlinxCoroutinesVersion = "1.1.1" 7 | 8 | plugins { 9 | kotlin("jvm") version "1.3.20" 10 | } 11 | 12 | tasks.withType { 13 | kotlinOptions.jvmTarget = "1.8" 14 | } 15 | 16 | dependencies { 17 | compile("org.jsoup:jsoup:1.11.3") 18 | compile("io.reactivex.rxjava2:rxkotlin:2.2.0") 19 | compile(kotlin("stdlib-jdk8", kotlinVersion)) 20 | compile(kotlin("reflect", kotlinVersion)) 21 | compile("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") 22 | compile("org.jetbrains.kotlinx:kotlinx-html-jvm:0.6.6") 23 | compile("com.google.code.gson:gson:2.8.2") 24 | compile("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.7") 25 | compile("org.slf4j:slf4j-api:1.7.14") 26 | compile("ch.qos.logback:logback-classic:1.1.3") 27 | compile("com.squareup.okhttp3:okhttp:3.9.1") 28 | testCompile(kotlin("test-junit", kotlinVersion)) 29 | testCompile("junit:junit:4.11") 30 | } 31 | 32 | repositories { 33 | mavenCentral() 34 | jcenter() 35 | } 36 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s1monw1/kotlin-samples/53e8ca89b3e87dc4bc34bcce427f2343861330e5/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.5-bin.zip 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStorePath=wrapper/dists 5 | zipStoreBase=GRADLE_USER_HOME 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 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 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /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 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 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 Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /src/main/java/de/swirtz/java/RuntimeTypeAdapterFactory.java: -------------------------------------------------------------------------------- 1 | package de.swirtz.java;/* 2 | * Copyright (C) 2011 Google Inc. 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 | import com.google.gson.*; 18 | import com.google.gson.internal.Streams; 19 | import com.google.gson.reflect.TypeToken; 20 | import com.google.gson.stream.JsonReader; 21 | import com.google.gson.stream.JsonWriter; 22 | 23 | import java.io.IOException; 24 | import java.util.LinkedHashMap; 25 | import java.util.Map; 26 | 27 | /** 28 | * Adapts values whose runtime type may differ from their declaration type. This 29 | * is necessary when a field's type is not the same type that GSON should create 30 | * when deserializing that field. For example, consider these types: 31 | *
   {@code
 32 |  *   abstract class Shape {
 33 |  *     int x;
 34 |  *     int y;
 35 |  *   }
 36 |  *   class Circle extends Shape {
 37 |  *     int radius;
 38 |  *   }
 39 |  *   class Rectangle extends Shape {
 40 |  *     int width;
 41 |  *     int height;
 42 |  *   }
 43 |  *   class Diamond extends Shape {
 44 |  *     int width;
 45 |  *     int height;
 46 |  *   }
 47 |  *   class Drawing {
 48 |  *     Shape bottomShape;
 49 |  *     Shape topShape;
 50 |  *   }
 51 |  * }
52 | *

Without additional type information, the serialized JSON is ambiguous. Is 53 | * the bottom shape in this drawing a rectangle or a diamond?

   {@code
 54 |  *   {
 55 |  *     "bottomShape": {
 56 |  *       "width": 10,
 57 |  *       "height": 5,
 58 |  *       "x": 0,
 59 |  *       "y": 0
 60 |  *     },
 61 |  *     "topShape": {
 62 |  *       "radius": 2,
 63 |  *       "x": 4,
 64 |  *       "y": 1
 65 |  *     }
 66 |  *   }}
67 | * This class addresses this problem by adding type information to the 68 | * serialized JSON and honoring that type information when the JSON is 69 | * deserialized:
   {@code
 70 |  *   {
 71 |  *     "bottomShape": {
 72 |  *       "type": "Diamond",
 73 |  *       "width": 10,
 74 |  *       "height": 5,
 75 |  *       "x": 0,
 76 |  *       "y": 0
 77 |  *     },
 78 |  *     "topShape": {
 79 |  *       "type": "Circle",
 80 |  *       "radius": 2,
 81 |  *       "x": 4,
 82 |  *       "y": 1
 83 |  *     }
 84 |  *   }}
85 | * Both the type field name ({@code "type"}) and the type labels ({@code 86 | * "Rectangle"}) are configurable. 87 | * 88 | *

Registering Types

89 | * Create a {@code RuntimeTypeAdapterFactory} by passing the base type and type field 90 | * name to the {@link #of} factory method. If you don't supply an explicit type 91 | * field name, {@code "type"} will be used.
   {@code
 92 |  *   RuntimeTypeAdapterFactory shapeAdapterFactory
 93 |  *       = RuntimeTypeAdapterFactory.of(Shape.class, "type");
 94 |  * }
95 | * Next register all of your subtypes. Every subtype must be explicitly 96 | * registered. This protects your application from injection attacks. If you 97 | * don't supply an explicit type label, the type's simple name will be used. 98 | *
   {@code
 99 |  *   shapeAdapter.registerSubtype(Rectangle.class, "Rectangle");
100 |  *   shapeAdapter.registerSubtype(Circle.class, "Circle");
101 |  *   shapeAdapter.registerSubtype(Diamond.class, "Diamond");
102 |  * }
103 | * Finally, register the type adapter factory in your application's GSON builder: 104 | *
   {@code
105 |  *   Gson gson = new GsonBuilder()
106 |  *       .registerTypeAdapterFactory(shapeAdapterFactory)
107 |  *       .create();
108 |  * }
109 | * Like {@code GsonBuilder}, this API supports chaining:
   {@code
110 |  *   RuntimeTypeAdapterFactory shapeAdapterFactory = RuntimeTypeAdapterFactory.of(Shape.class)
111 |  *       .registerSubtype(Rectangle.class)
112 |  *       .registerSubtype(Circle.class)
113 |  *       .registerSubtype(Diamond.class);
114 |  * }
115 | */ 116 | public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { 117 | private final Class baseType; 118 | private final String typeFieldName; 119 | private final Map> labelToSubtype = new LinkedHashMap>(); 120 | private final Map, String> subtypeToLabel = new LinkedHashMap, String>(); 121 | 122 | private RuntimeTypeAdapterFactory(Class baseType, String typeFieldName) { 123 | if (typeFieldName == null || baseType == null) { 124 | throw new NullPointerException(); 125 | } 126 | 127 | this.baseType = baseType; 128 | this.typeFieldName = typeFieldName; 129 | 130 | } 131 | 132 | /** 133 | * Creates a new runtime type adapter using for {@code baseType} using {@code 134 | * typeFieldName} as the type field name. Type field names are case sensitive. 135 | */ 136 | public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName) { 137 | return new RuntimeTypeAdapterFactory(baseType, typeFieldName); 138 | } 139 | 140 | /** 141 | * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as 142 | * the type field name. 143 | */ 144 | public static RuntimeTypeAdapterFactory of(Class baseType) { 145 | return new RuntimeTypeAdapterFactory(baseType, "type"); 146 | } 147 | 148 | /** 149 | * Registers {@code type} identified by {@code label}. Labels are case 150 | * sensitive. 151 | * 152 | * @throws IllegalArgumentException if either {@code type} or {@code label} 153 | * have already been registered on this type adapter. 154 | */ 155 | public RuntimeTypeAdapterFactory registerSubtype(Class type, String label) { 156 | if (type == null || label == null) { 157 | throw new NullPointerException(); 158 | } 159 | if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) { 160 | throw new IllegalArgumentException("types and labels must be unique"); 161 | } 162 | labelToSubtype.put(label, type); 163 | subtypeToLabel.put(type, label); 164 | return this; 165 | } 166 | 167 | /** 168 | * Registers {@code type} identified by its {@link Class#getSimpleName simple 169 | * name}. Labels are case sensitive. 170 | * 171 | * @throws IllegalArgumentException if either {@code type} or its simple name 172 | * have already been registered on this type adapter. 173 | */ 174 | public RuntimeTypeAdapterFactory registerSubtype(Class type) { 175 | return registerSubtype(type, type.getSimpleName()); 176 | } 177 | 178 | public TypeAdapter create(Gson gson, TypeToken type) { 179 | if (type.getRawType() != baseType) { 180 | return null; 181 | } 182 | 183 | final Map> labelToDelegate 184 | = new LinkedHashMap>(); 185 | final Map, TypeAdapter> subtypeToDelegate 186 | = new LinkedHashMap, TypeAdapter>(); 187 | for (Map.Entry> entry : labelToSubtype.entrySet()) { 188 | TypeAdapter delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue())); 189 | labelToDelegate.put(entry.getKey(), delegate); 190 | subtypeToDelegate.put(entry.getValue(), delegate); 191 | } 192 | 193 | return new TypeAdapter() { 194 | @Override public R read(JsonReader in) throws IOException { 195 | JsonElement jsonElement = Streams.parse(in); 196 | JsonElement labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); 197 | if (labelJsonElement == null) { 198 | throw new JsonParseException("cannot deserialize " + baseType 199 | + " because it does not define a field named " + typeFieldName); 200 | } 201 | String label = labelJsonElement.getAsString(); 202 | @SuppressWarnings("unchecked") // registration requires that subtype extends T 203 | TypeAdapter delegate = (TypeAdapter) labelToDelegate.get(label); 204 | if (delegate == null) { 205 | throw new JsonParseException("cannot deserialize " + baseType + " subtype named " 206 | + label + "; did you forget to register a subtype?"); 207 | } 208 | return delegate.fromJsonTree(jsonElement); 209 | } 210 | 211 | @Override public void write(JsonWriter out, R value) throws IOException { 212 | Class srcType = value.getClass(); 213 | String label = subtypeToLabel.get(srcType); 214 | @SuppressWarnings("unchecked") // registration requires that subtype extends T 215 | TypeAdapter delegate = (TypeAdapter) subtypeToDelegate.get(srcType); 216 | if (delegate == null) { 217 | throw new JsonParseException("cannot serialize " + srcType.getName() 218 | + "; did you forget to register a subtype?"); 219 | } 220 | JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); 221 | if (jsonObject.has(typeFieldName)) { 222 | throw new JsonParseException("cannot serialize " + srcType.getName() 223 | + " because it already defines a field named " + typeFieldName); 224 | } 225 | JsonObject clone = new JsonObject(); 226 | clone.add(typeFieldName, new JsonPrimitive(label)); 227 | for (Map.Entry e : jsonObject.entrySet()) { 228 | clone.add(e.getKey(), e.getValue()); 229 | } 230 | Streams.write(clone, out); 231 | } 232 | }.nullSafe(); 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /src/main/kotlin/TopKtSOParser.kt: -------------------------------------------------------------------------------- 1 | import org.jsoup.Jsoup 2 | import org.jsoup.nodes.Document 3 | import org.jsoup.nodes.Element 4 | import java.net.URL 5 | 6 | private fun Element.hasChildTag(tagName: String) = children().any { it.tagName() == tagName } 7 | 8 | private fun Element.findAllTimeTitle(): Element? { 9 | if (this.ownText() == "All Time" && parent().hasChildTag("table")) { 10 | return this 11 | } else { 12 | children().forEach { child -> 13 | val node = child.findAllTimeTitle() 14 | if (node != null) { 15 | return node 16 | } 17 | } 18 | } 19 | return null 20 | } 21 | 22 | data class ScoreEntry(val name: String, val score: Int) 23 | 24 | private fun Document.getScoreEntries(): List { 25 | val allTimeTitle = this.findAllTimeTitle() ?: throw IllegalStateException("No title found in document $this") 26 | 27 | val table = allTimeTitle.parent().child(1) 28 | val tableBody = table.child(0) 29 | 30 | val rows = tableBody.children() 31 | 32 | return rows.map { row -> 33 | val score = row.child(0).child(0).attr("title").substringAfterLast(' ').toInt() 34 | val name = row.child(2).selectFirst(".user-details").child(0).text() 35 | ScoreEntry(name, score) 36 | } 37 | } 38 | 39 | fun main() { 40 | 41 | data class Archive(val date: String, val url: String) 42 | 43 | URL("http://web.archive.org/cdx/search/cdx?url=https://stackoverflow.com/tags/kotlin/topusers") 44 | .readText() 45 | .lineSequence() 46 | .filter { it.isNotBlank() } 47 | .map { archiveStr -> 48 | val split = archiveStr.split(' ') 49 | Archive(date = split[1], url = "http://web.archive.org/web/${split[1]}/${split[2]}/") 50 | } 51 | .map { archive -> 52 | println("Fetching URL ${archive.url}") 53 | val document: Document = Jsoup.parse(URL(archive.url), 60 * 1000) 54 | document.getScoreEntries() 55 | } 56 | .forEach { 57 | println(it) 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/conventions/Fraction.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.conventions 2 | 3 | data class Fraction(val numerator: Int, val denominator: Int) : Comparable { 4 | 5 | val decimal by lazy { numerator.toDouble() / denominator } 6 | 7 | override fun compareTo(other: Fraction) = decimal.compareTo(other.decimal) 8 | 9 | override fun toString() = "$numerator/$denominator" 10 | 11 | //unary operators 12 | operator fun unaryMinus() = Fraction(-this.numerator, this.denominator) 13 | 14 | //binary operators 15 | operator fun plus(add: Fraction) = 16 | if (this.denominator == add.denominator) Fraction(this.numerator + add.numerator, denominator) 17 | else { 18 | val a = this * add.denominator 19 | val b = add * this.denominator 20 | Fraction(a.numerator + b.numerator, a.denominator) 21 | } 22 | 23 | operator fun times(num: Int) = Fraction(numerator * num, denominator * num) 24 | 25 | //increments 26 | operator fun dec() = Fraction(this.numerator - 1, this.denominator) 27 | 28 | 29 | //invoke convention 30 | operator fun invoke(prefix: String = "") = println(prefix + toString()) 31 | } 32 | 33 | 34 | operator fun Fraction.get(ind: Int) = 35 | when (ind) { 36 | 0 -> numerator 37 | 1 -> denominator 38 | else -> IllegalArgumentException("Index must be 0 or 1") 39 | } 40 | 41 | operator fun Fraction.inc() = Fraction(this.numerator + 1, this.denominator) 42 | 43 | operator fun ClosedRange.iterator() = 44 | object : Iterator { 45 | var curr: Fraction = start 46 | override fun hasNext() = curr <= endInclusive 47 | override fun next() = curr++ 48 | 49 | } 50 | 51 | fun main(args: Array) { 52 | println(Fraction(2, 3)) 53 | 54 | var sum = Fraction(2, 3) + Fraction(3, 2) 55 | println("Sum: ${sum.decimal}") 56 | //invoke 57 | sum("My invoke prefix: ") 58 | println("3/2 > 2/2: ${Fraction(3, 2) > Fraction(2, 2)}") 59 | println("1/2 <= 2/4: ${Fraction(1, 2) <= Fraction(2, 4)}") 60 | println("Sum after inc: ${++sum}") 61 | println("Sum after dec: ${--sum}") 62 | println("Sum negated: ${-sum}") 63 | println("Sum numerator: ${sum[0]}") 64 | 65 | val fracRange = Fraction(1, 5)..Fraction(5, 7) 66 | println(Fraction(3, 5) in fracRange) 67 | for (i in fracRange) { 68 | println("Next: $i") 69 | } 70 | 71 | val f = Fraction(2, 3) 72 | val (a, b) = f 73 | println("Destructed sum to: ($a, $b)") 74 | } 75 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/coroutines/ActorExample.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.coroutines 2 | 3 | import kotlinx.coroutines.GlobalScope 4 | import kotlinx.coroutines.channels.Channel 5 | import kotlinx.coroutines.channels.SendChannel 6 | import kotlinx.coroutines.channels.actor 7 | import kotlinx.coroutines.delay 8 | import kotlinx.coroutines.launch 9 | import kotlinx.coroutines.runBlocking 10 | 11 | sealed class CounterMsg { 12 | object IncCounter : CounterMsg() // one-way message to increment counter 13 | class GetCounter(val response: SendChannel) : CounterMsg() // a request with channel for reply. 14 | } 15 | 16 | // This function launches a new counter actor 17 | fun counterActor() = GlobalScope.actor { 18 | var counter = 0 // actor state, not shared 19 | for (msg in channel) { // handle incoming messages 20 | when (msg) { 21 | is CounterMsg.IncCounter -> counter++ 22 | is CounterMsg.GetCounter -> msg.response.send(counter) 23 | } 24 | } 25 | } 26 | 27 | suspend fun getCurrentCount(counter: SendChannel): Int { 28 | val response = Channel() 29 | counter.send(CounterMsg.GetCounter(response)) 30 | val receive = response.receive() 31 | println("Counter = $receive") 32 | return receive 33 | } 34 | 35 | fun main(args: Array) = runBlocking { 36 | val counter = counterActor() 37 | 38 | GlobalScope.launch { 39 | while (getCurrentCount(counter) < 100) { 40 | delay(100) 41 | println("sending IncCounter message") 42 | counter.send(CounterMsg.IncCounter) 43 | } 44 | } 45 | 46 | GlobalScope.launch { 47 | while (getCurrentCount(counter) < 100) { 48 | delay(200) 49 | } 50 | }.join() 51 | counter.close() // shutdown the actor 52 | } 53 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/coroutines/AsyncAwaitFun.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.coroutines 2 | 3 | import java.security.InvalidAlgorithmParameterException 4 | import java.util.Random 5 | import java.util.concurrent.ThreadLocalRandom 6 | 7 | 8 | object Random { 9 | 10 | private fun > checkConditions(left: T, right: T, leftLowerBound: T) { 11 | if (left < leftLowerBound) { 12 | throw InvalidAlgorithmParameterException( 13 | "Left limit can 't be negative" 14 | ) 15 | } else if (right <= left) { 16 | throw InvalidAlgorithmParameterException( 17 | "Right limit can't be less or equal than left limit" 18 | ) 19 | } 20 | } 21 | 22 | internal fun generatePositiveFloat( 23 | leftLimit: Float = Float.MIN_VALUE, 24 | rightLimit: Float = Float.MAX_VALUE 25 | ): Float { 26 | checkConditions(leftLimit, rightLimit, 0F) 27 | return Random().nextFloat() 28 | } 29 | 30 | 31 | internal fun generatePositiveShort( 32 | leftLimit: Short = 0, 33 | rightLimit: Short = Short.MAX_VALUE 34 | ): Short { 35 | checkConditions(leftLimit, rightLimit, leftLimit) 36 | 37 | return ThreadLocalRandom.current().nextInt( 38 | leftLimit.toInt(), 39 | rightLimit.toInt() 40 | ).toShort() 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/coroutines/CancelCoroutine.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.coroutines 2 | 3 | import kotlinx.coroutines.* 4 | 5 | fun main(args: Array) = runBlocking { 6 | val startTime = System.currentTimeMillis() 7 | val jobs = arrayListOf() 8 | jobs += GlobalScope.launch { 9 | var nextPrintTime = startTime 10 | var i = 0 11 | while (isActive) { // check if still active 12 | if (System.currentTimeMillis() >= nextPrintTime) { 13 | println("Job1: Sleeping ${i++} ...") 14 | nextPrintTime += 500L 15 | } 16 | } 17 | } 18 | 19 | //another job 20 | jobs += GlobalScope.launch { 21 | while (isActive) { // check if still active 22 | if (System.currentTimeMillis() >= 42) { 23 | println("Job2: Sleeping 42 ...") 24 | delay(500L) 25 | } 26 | } 27 | } 28 | delay(1300L) // delay a bit 29 | println("main: Cancelling the sleeping job!") 30 | jobs.forEach { it.cancelAndJoin() } // cancels the job and waits for its completion 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/coroutines/CancellationExample.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.coroutines 2 | 3 | import kotlinx.coroutines.* 4 | 5 | fun main(args: Array) = runBlocking { 6 | val outer = launch { 7 | try { 8 | launch(coroutineContext) { 9 | try { 10 | // work here 11 | println("wait inner") 12 | delay(5000) 13 | } catch (ex: CancellationException) { 14 | println("In inner catch:CancellationException") 15 | } 16 | println("inner done") 17 | } 18 | println("wait outer") 19 | try { 20 | delay(400) 21 | } catch (ex: CancellationException) { 22 | println("In delay catch:CancellationException") 23 | } 24 | 25 | } catch (ex: CancellationException) { 26 | println("In outer catch:CancellationException") 27 | } 28 | 29 | } 30 | 31 | delay(300) // give it a chance to run 32 | outer.cancelChildren() 33 | println(outer.isCancelled) 34 | println(outer.isCompleted) 35 | outer.join() 36 | println(outer.isCompleted) 37 | 38 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/coroutines/CoroutineFun.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.coroutines 2 | 3 | import kotlinx.coroutines.* 4 | import org.slf4j.LoggerFactory 5 | import java.time.Instant 6 | import java.time.ZoneId 7 | 8 | val LOG = LoggerFactory.getLogger("CoroutineFun-Example") 9 | 10 | fun main(args: Array) { 11 | fun getTime(): Instant { 12 | return Instant.now().atZone(ZoneId.systemDefault()).toInstant() 13 | } 14 | 15 | LOG.debug("${getTime()}: Start") 16 | 17 | // Start a coroutine 18 | GlobalScope.launch { 19 | delay(1000) 20 | LOG.debug("${getTime()}: Hello from coroutine") 21 | } 22 | 23 | runBlocking { 24 | delay(1500) 25 | LOG.debug("${getTime()}: Hello from second coroutine ") 26 | } 27 | LOG.debug("${getTime()}: Stop") 28 | 29 | val deferred = (1..1_000_000).map { n -> 30 | GlobalScope.async { n } 31 | } 32 | 33 | runBlocking { 34 | val sum = deferred.sumBy { it.await() } 35 | println("Sum: $sum") 36 | } 37 | 38 | 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/coroutines/CoroutineScopingExample.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.coroutines 2 | 3 | import kotlinx.coroutines.coroutineScope 4 | import kotlinx.coroutines.delay 5 | import kotlinx.coroutines.launch 6 | import kotlinx.coroutines.runBlocking 7 | 8 | fun main(args: Array) = runBlocking { 9 | coroutineScope { 10 | val outerLaunch = launch { 11 | launch { 12 | while (true) { 13 | delay(300) 14 | println("Hello from first inner launch") 15 | } 16 | } 17 | launch { 18 | while (true) { 19 | delay(300) 20 | println("Hello from second inner launch") 21 | } 22 | } 23 | } 24 | 25 | println("Hello from runBlocking after outer launch") 26 | delay(800) 27 | outerLaunch.cancel() 28 | } 29 | println("finished coroutineScope") 30 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/coroutines/CoroutineSingleThreaded.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.coroutines 2 | 3 | import kotlinx.coroutines.* 4 | 5 | 6 | fun main(args: Array) { 7 | val context = newSingleThreadContext("launch-SingleThread") 8 | runBlocking { 9 | val s = System.currentTimeMillis() 10 | var i = 0 11 | 12 | List(1_000_000) { 13 | CoroutineScope(context).launch(CoroutineName("myroutine")) { 14 | i += 1 15 | } 16 | }.forEach { it.join() } 17 | 18 | println("Value: $i, Duration: ${System.currentTimeMillis() - s}") 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/coroutines/EmailExample.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.coroutines 2 | 3 | import kotlinx.coroutines.* 4 | 5 | 6 | suspend fun getReceiverAddressFromDatabase(): String { 7 | delay(1000) 8 | return "coroutine@kotlin.org" 9 | } 10 | 11 | suspend fun sendEmail(r: String, msg: String): Boolean { 12 | delay(2000) 13 | println("Sent '$msg' to $r") 14 | return true 15 | } 16 | 17 | suspend fun sendEmailSuspending(): Boolean { 18 | val msg = GlobalScope.async { 19 | delay(500) 20 | "The message content" 21 | } 22 | val recipient = GlobalScope.async { getReceiverAddressFromDatabase() } 23 | println("Waiting for email data") 24 | 25 | val sendStatus = GlobalScope.async { 26 | sendEmail(recipient.await(), msg.await()) 27 | } 28 | return sendStatus.await() 29 | } 30 | 31 | fun main(args: Array) = runBlocking { 32 | val job = GlobalScope.launch { 33 | sendEmailSuspending() 34 | println("Email sent successfully.") 35 | } 36 | job.join() 37 | println("Finished") 38 | 39 | } 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/coroutines/MutableStateAtomic.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.coroutines 2 | 3 | import kotlinx.coroutines.CoroutineName 4 | import kotlinx.coroutines.GlobalScope 5 | import kotlinx.coroutines.launch 6 | import kotlinx.coroutines.runBlocking 7 | import java.time.Instant 8 | import java.time.ZoneId 9 | import java.util.concurrent.atomic.AtomicInteger 10 | 11 | /** 12 | * 13 | * File created on 05.07.2017. 14 | */ 15 | 16 | fun main(args: Array) { 17 | fun getTime(): Instant { 18 | return Instant.now().atZone(ZoneId.systemDefault()).toInstant() 19 | } 20 | 21 | val start = getTime() 22 | LOG.debug("$start: Start") 23 | 24 | val c = AtomicInteger() 25 | runBlocking(CoroutineName("blockingRoutine")) { 26 | GlobalScope.launch { 27 | val jobs = List(1_000_000) { 28 | launch { 29 | c.incrementAndGet() 30 | } 31 | } 32 | jobs.forEach { it.join() } 33 | }.join() 34 | } 35 | val end = getTime() 36 | LOG.debug("$end: End") 37 | LOG.debug("Duration: ${end.epochSecond - start.epochSecond}") 38 | println(c) 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/coroutines/MutableStateConfinement.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.coroutines 2 | 3 | import kotlinx.coroutines.CoroutineName 4 | import kotlinx.coroutines.launch 5 | import kotlinx.coroutines.newSingleThreadContext 6 | import kotlinx.coroutines.runBlocking 7 | import java.time.Instant 8 | import java.time.ZoneId 9 | 10 | /** 11 | * 12 | * File created on 05.07.2017. 13 | */ 14 | 15 | fun main(args: Array) { 16 | fun getTime(): Instant = Instant.now().atZone(ZoneId.systemDefault()).toInstant() 17 | val start = getTime().also { LOG.debug("$it: Start") } 18 | 19 | var count = 0 20 | runBlocking(CoroutineName("blockingRoutine")) { 21 | launch(newSingleThreadContext("mysinglethread")) { 22 | val jobs = List(1_000_000) { 23 | launch(coroutineContext) { 24 | count += 1 25 | } 26 | } 27 | jobs.forEach { it.join() } 28 | } 29 | } 30 | val end = getTime().also { LOG.debug("$it: End") } 31 | LOG.debug("Duration: ${end.epochSecond - start.epochSecond} s") 32 | println("Counter: $count") 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/coroutines/ObserveContinuation.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.coroutines 2 | 3 | import kotlinx.coroutines.GlobalScope 4 | import kotlinx.coroutines.delay 5 | import kotlinx.coroutines.launch 6 | 7 | suspend fun sampleSuspendFun(x: Int): Int { 8 | delay(2000) 9 | return x * x 10 | } 11 | 12 | 13 | fun main(args: Array) { 14 | GlobalScope.launch { 15 | sampleSuspendFun(5) 16 | print("Hello!") 17 | } 18 | 19 | } 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/delegation/DelegatedLazyMutable.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.delegation 2 | 3 | import kotlin.properties.ReadWriteProperty 4 | import kotlin.reflect.KProperty 5 | 6 | fun main(args: Array) { 7 | class X { 8 | var currentContextProvider: String by LazyMutable { 9 | println("lazy calculate:") 10 | "myfirstValue" 11 | } 12 | } 13 | 14 | with(X()) { 15 | println(currentContextProvider) 16 | println(currentContextProvider) 17 | currentContextProvider = "anything" 18 | println(currentContextProvider) 19 | 20 | } 21 | 22 | } 23 | 24 | class LazyMutable(val initializer: () -> T) : ReadWriteProperty { 25 | private object UNINITIALIZED_VALUE 26 | 27 | private var prop: Any? = UNINITIALIZED_VALUE 28 | 29 | @Suppress("UNCHECKED_CAST") 30 | override fun getValue(thisRef: Any?, property: KProperty<*>): T { 31 | return if (prop == UNINITIALIZED_VALUE) { 32 | synchronized(this) { 33 | return if (prop == UNINITIALIZED_VALUE) initializer().also { prop = it } else prop as T 34 | } 35 | } else prop as T 36 | } 37 | 38 | override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { 39 | synchronized(this) { 40 | prop = value 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/delegation/DelegatedThisContext.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.delegation 2 | 3 | import kotlin.properties.ReadOnlyProperty 4 | import kotlin.reflect.KProperty 5 | 6 | /** 7 | * The initializer will be called once, on first access. The current instance (in which the lazy property is defined) 8 | * will be passed into that block. 9 | */ 10 | class LazyThisContext(private val initializer: (Any?) -> T) : ReadOnlyProperty { 11 | private object UNINITIALIZED_VALUE 12 | 13 | private var prop: Any? = UNINITIALIZED_VALUE 14 | 15 | @Suppress("UNCHECKED_CAST") 16 | override fun getValue(thisRef: Any?, property: KProperty<*>): T { 17 | return if (prop == UNINITIALIZED_VALUE) { 18 | synchronized(this) { 19 | return if (prop == UNINITIALIZED_VALUE) { 20 | //invoke the initializer block with thisRef 21 | initializer(thisRef).also { prop = it } 22 | } else { 23 | prop as T 24 | } 25 | } 26 | } else prop as T 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/delegation/PropertyDelegation.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.delegation 2 | 3 | import kotlin.reflect.KMutableProperty 4 | import kotlin.reflect.KProperty 5 | import kotlin.reflect.jvm.javaField 6 | 7 | 8 | class Comp2(var xProp: String, val yProp: String) 9 | 10 | class Comp1(private val comp: Comp2) { 11 | var a by delegated(comp::xProp) 12 | } 13 | 14 | fun delegated(prop: KMutableProperty) = MutablePropertyDelegate(prop) 15 | 16 | class MutablePropertyDelegate(private val prop: KMutableProperty) { 17 | private fun ensureDifference(prop1: KProperty, prop2: KProperty) { 18 | if (prop1.javaField == prop2.javaField) throw IllegalArgumentException("Can't delegate to same property.") 19 | } 20 | 21 | operator fun getValue(thisRef: Any?, property: KProperty<*>): R { 22 | ensureDifference(prop, property) 23 | return prop.getter.call() 24 | } 25 | 26 | operator fun setValue(thisRef: Any?, property: KProperty<*>, value: R) { 27 | ensureDifference(prop, property) 28 | return prop.setter.call(value) 29 | } 30 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/dsl/CsvToSql.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.dsl 2 | 3 | import java.io.InputStream 4 | import java.io.OutputStream 5 | import java.nio.file.Files 6 | import java.nio.file.Path 7 | import java.nio.file.Paths 8 | 9 | fun generateSQLInsert(init: SQLGeneratorConfig.() -> Unit) { 10 | val config = SQLGeneratorConfig(SQLGeneratorConfig.Operation.INSERT).apply(init) 11 | config.convertToSql() 12 | } 13 | 14 | class SQLGeneratorConfig(val op: Operation) { 15 | 16 | enum class Operation { 17 | INSERT; 18 | } 19 | 20 | private var inputStream: InputStream? = null 21 | private var outputStream: OutputStream? = null 22 | var tableName: String? = null 23 | var separator: String? = ";" 24 | 25 | fun input(s: InputStream) { 26 | inputStream = s 27 | } 28 | 29 | fun fromFile(p: Path) { 30 | inputStream = Files.newInputStream(p) 31 | } 32 | 33 | fun writeResultTo(out: OutputStream) { 34 | outputStream = out 35 | } 36 | 37 | fun writeResultToFile(file: Path) { 38 | outputStream = Files.newOutputStream(file) 39 | } 40 | 41 | private fun String.csvParts(separator: String = ";") = split(separator) 42 | 43 | //Only works with String columns 44 | internal fun convertToSql(): String { 45 | return when (op) { 46 | Operation.INSERT -> convertToSqlInsert() 47 | else -> throw NotImplementedError() 48 | } 49 | } 50 | 51 | private fun convertToSqlInsert(): String { 52 | val csvLines = inputStream?.reader()?.readLines() 53 | ?: throw IllegalStateException("inputStream in config must be set.") 54 | val tableName = tableName ?: throw IllegalStateException("inputStream in config must be set.") 55 | val separator = separator ?: ";" 56 | 57 | val sql = StringBuilder( 58 | "INSERT INTO `$tableName` (${csvLines[0].csvParts(separator).joinToString(",") { "`$it`" }}) \nVALUES" 59 | ) 60 | 61 | csvLines.drop(1).joinToString(separator = ",", postfix = ";") { 62 | "\n\t(${it.csvParts(separator).joinToString(",") { "'$it'" }})" 63 | }.apply { sql.append(this) } 64 | return sql.toString().apply { 65 | outputStream?.let { 66 | this.byteInputStream().copyTo(it) 67 | } 68 | } 69 | } 70 | 71 | 72 | } 73 | 74 | 75 | fun main(args: Array) { 76 | 77 | generateSQLInsert { 78 | fromFile(Paths.get("src/main/resources/ui_glossary_optimizer.csv")) 79 | tableName = "ui_glossary" 80 | writeResultTo(System.out) 81 | } 82 | } 83 | 84 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/dsl/DSL.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.dsl 2 | 3 | interface Element { 4 | fun render(builder: StringBuilder, indent: String) 5 | } 6 | 7 | class TextElement(val text: String) : Element { 8 | override fun render(builder: StringBuilder, indent: String) { 9 | builder.append("$indent$text\n") 10 | } 11 | } 12 | 13 | @DslMarker 14 | annotation class HtmlTagMarker 15 | 16 | @HtmlTagMarker 17 | abstract class Tag(val name: String) : Element { 18 | val children = arrayListOf() 19 | val attributes = hashMapOf() 20 | 21 | protected fun initTag(tag: T, init: T.() -> Unit): T { 22 | tag.init() 23 | children.add(tag) 24 | return tag 25 | } 26 | 27 | override fun render(builder: StringBuilder, indent: String) { 28 | builder.append("$indent<$name${renderAttributes()}>\n") 29 | for (c in children) { 30 | c.render(builder, indent + " ") 31 | } 32 | builder.append("$indent\n") 33 | } 34 | 35 | private fun renderAttributes(): String { 36 | val builder = StringBuilder() 37 | for ((attr, value) in attributes) { 38 | builder.append(" $attr=\"$value\"") 39 | } 40 | return builder.toString() 41 | } 42 | 43 | override fun toString(): String { 44 | val builder = StringBuilder() 45 | render(builder, "") 46 | return builder.toString() 47 | } 48 | } 49 | 50 | abstract class TagWithText(name: String) : Tag(name) { 51 | operator fun String.unaryPlus() { 52 | children.add(TextElement(this)) 53 | } 54 | } 55 | 56 | class HTML : TagWithText("html") { 57 | fun head(init: Head.() -> Unit) = initTag(Head(), init) 58 | 59 | fun body(init: Body.() -> Unit) = initTag(Body(), init) 60 | } 61 | 62 | class Head : TagWithText("head") { 63 | fun title(init: Title.() -> Unit) = initTag(Title(), init) 64 | } 65 | 66 | class Title : TagWithText("title") 67 | 68 | abstract class BodyTag(name: String) : TagWithText(name) { 69 | fun b(init: B.() -> Unit) = initTag(B(), init) 70 | fun p(init: P.() -> Unit) = initTag(P(), init) 71 | fun h1(init: H1.() -> Unit) = initTag(H1(), init) 72 | fun a(href: String, init: A.() -> Unit) { 73 | val a = initTag(A(), init) 74 | a.href = href 75 | } 76 | } 77 | 78 | class Body : BodyTag("body") 79 | class B : BodyTag("b") 80 | class P : BodyTag("p") 81 | class H1 : BodyTag("h1") 82 | 83 | class A : BodyTag("a") { 84 | var href: String 85 | get() = attributes["href"]!! 86 | set(value) { 87 | attributes["href"] = value 88 | } 89 | } 90 | 91 | fun html(init: HTML.() -> Unit): HTML { 92 | val html = HTML() 93 | html.init() 94 | return html 95 | } 96 | 97 | 98 | 99 | fun main(args: Array) { 100 | val result = html { 101 | head { 102 | title { +"My Document" } 103 | } 104 | body { 105 | h1 { +"My Header" } 106 | p { 107 | +"first para" 108 | a("uri") { 109 | b { +"bold" } 110 | } 111 | } 112 | p { 113 | +"theEnd" 114 | } 115 | } 116 | } 117 | 118 | //println(result) 119 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/generics/ClassWithTypeParam.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.generics 2 | 3 | /** 4 | * Created on 09.03.2017. 5 | * @author: simon-wirtz 6 | * 7 | * What 'out' means: You can think of ClassWithTypeParam as being a producer of T's, and NOT a consumer of T's. 8 | */ 9 | class ClassWithTypeParam(t: T) { 10 | private val type = t 11 | 12 | fun getTypeMember() = type 13 | } 14 | 15 | fun main(args: Array) { 16 | val c1 = ClassWithTypeParam(123) 17 | val member1: Int = c1.getTypeMember() 18 | //type param can be inferred because of constructor argument 19 | val c2 = ClassWithTypeParam("StringParam") 20 | val member2: String = c2.getTypeMember() 21 | println("Member of Int-ParamType: $member1\nMember of String-ParamType: $member2") 22 | 23 | //declaration-side variance; notice the 'out' keyword in TypeParam-declaration of ClassWithTypeParam; 24 | //this means: class only produces T's (get-method) 25 | val objects: ClassWithTypeParam = c2 26 | val objectFromClass = objects.getTypeMember() 27 | println("Member of Object-ParamType: $objectFromClass") 28 | 29 | val ints: Array = arrayOf(1, 2, 3) 30 | val any: Array = arrayOf(3, 2, 1) 31 | println(ints) 32 | copy(ints, any) 33 | // not allowed!! copy(any, ints) 34 | 35 | var intList: List = genericFunction("String-List expected") 36 | val stringList: List = genericFunction(11) 37 | 38 | } 39 | 40 | //from is projected, use-site variance 41 | fun copy(from: Array, to: Array) { 42 | println("copy called") 43 | to[0] = from[0] 44 | } 45 | 46 | fun genericFunction(item: T): List = arrayListOf(item) -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/inheritance/Animal.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.inheritance 2 | 3 | /** 4 | * Created on 09.03.2017. 5 | * @author: simon-wirtz 6 | */ 7 | abstract class Animal(val name: String) { 8 | fun notOpenFunction() = "I'm not an open function and cannot be overridden" 9 | abstract fun abstractFunction(): String // MUST be overriden 10 | open fun openFunction(): String = "I'm an open function and I can be overriden" 11 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/inheritance/Cat.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.inheritance 2 | 3 | import org.slf4j.LoggerFactory 4 | 5 | val LOG = LoggerFactory.getLogger(Cat::class.java.name) 6 | 7 | /** 8 | * Created on 09.03.2017. 9 | * @author: simon-wirtz 10 | */ 11 | class Cat(val catName: String) : Animal(catName), ExampleInterface { 12 | 13 | override fun abstractFunction(): String = "Meow" 14 | 15 | override fun openFunction(): String { 16 | LOG.debug("Overriding open function") 17 | //openFunction is known in both: ExampleInterface and Animal 18 | LOG.debug("open function of Animal: ${super.openFunction()}") 19 | LOG.debug("open function of ExampleInterface: ${super.openFunction()}") 20 | return "Overriding open function finished" 21 | } 22 | //not working because method is final: override fun notOpenFunction() = "trying to override" 23 | 24 | override fun interfaceFunction() = "Override of interface function" 25 | 26 | //Override of Any-methods 27 | override fun hashCode(): Int = catName.hashCode() 28 | 29 | override fun toString(): String = "Cat(catName='$catName')" 30 | 31 | override fun equals(other: Any?): Boolean { 32 | if (this === other) return true 33 | if (other?.javaClass != javaClass) return false 34 | other as Cat 35 | if (catName != other.catName) return false 36 | return true 37 | } 38 | } 39 | 40 | fun main(args: Array) { 41 | with(Cat("cat")) { 42 | LOG.debug("Cat created: $this") 43 | LOG.debug("Cat abstractFunction: ${abstractFunction()}") 44 | LOG.debug("Cat openFunction: ${openFunction()}") 45 | LOG.debug("Cat notOpenFunction: ${notOpenFunction()}") 46 | LOG.debug("Cat interfaceFunction: ${interfaceFunction()}") 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/inheritance/ExampleInterface.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.inheritance 2 | 3 | /** 4 | * Created on 09.03.2017. 5 | * @author: simon-wirtz 6 | */ 7 | interface ExampleInterface { 8 | 9 | /** 10 | * As in Java8 interfaces can provide default implementations 11 | */ 12 | fun openFunction() = "openFunction ExampleInterface" 13 | 14 | /** 15 | * This function is implicitly abstract 16 | */ 17 | fun interfaceFunction():String 18 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/inheritance/sealed/SealedMammal.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.inheritance.sealed 2 | 3 | sealed class Mammal(val name: String) 4 | 5 | class Cat(val catName: String) : Mammal(catName) 6 | data class Human(val humanName: String, val job: String) : Mammal(humanName) 7 | 8 | fun main(args: Array) { 9 | println(greetMammal(Cat("Garfield"))) 10 | println(greetMammal(Human("Peter", "Designer"))) 11 | } 12 | 13 | fun greetMammal(mammal: Mammal): String = when (mammal) { 14 | is Human -> "Hello ${mammal.name}; You're working as a ${mammal.job}" 15 | is Cat -> "Hello ${mammal.name}" 16 | } 17 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/inline/InlineClassBoxingExample.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.inline 2 | 3 | inline class WrappedInt(val value: Int) 4 | 5 | //In byte code we use boxed type 6 | fun take(w: WrappedInt?) { 7 | if (w != null) println(w.value) 8 | } 9 | 10 | 11 | fun main() { 12 | take(WrappedInt(5)) 13 | } 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/inline/InlineClassSubtypeExample.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.inline 2 | 3 | import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper 4 | import com.fasterxml.jackson.module.kotlin.readValue 5 | 6 | inline class JsonString(val value: String) 7 | 8 | data class JsonData(val x: Int, val y: Int) 9 | 10 | inline fun JsonString.asJson() = jacksonObjectMapper().readValue(this.value) 11 | 12 | fun main() { 13 | val jsonString = JsonString("""{ "x":200, "y":300 }""") 14 | val data: JsonData = jsonString.asJson() 15 | val nonJsonString = "whatever" 16 | nonJsonString.asJson() 17 | 18 | 19 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/inline/InlineClassTypingExample.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.inline 2 | 3 | inline class Password(val value: String) 4 | inline class UserName(val value: String) 5 | 6 | fun auth(userName: String, password: String){} 7 | fun auth(userName: UserName, password: Password){} 8 | 9 | fun main() { 10 | auth(UserName("user1"), Password("12345")) 11 | //does not compile due to type mismatch 12 | //auth(Password("12345"), UserName("user1")) 13 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/lambda/ApplyExample.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.lambda 2 | 3 | class GuiContainer { 4 | var width: Int = 0 5 | var height: Int = 0 6 | var background: String = "red" 7 | fun printMe() = println("I'm a container: $this") 8 | } 9 | 10 | 11 | fun main(args: Array) { 12 | val container = GuiContainer().apply { 13 | width = 10 14 | height = 20 15 | background = "blueish" 16 | printMe() 17 | } 18 | 19 | val nullable: String? = "anything" 20 | nullable?.let { 21 | println(it) 22 | } 23 | 24 | } 25 | 26 | class AlsoTester { 27 | var state: Int = 0 28 | 29 | fun next(): Int { 30 | //do some crazy stuff 31 | return 1.also { state = it } 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/lambda/LambdaFun.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.lambda 2 | 3 | /** 4 | * Created on 06.03.2017. 5 | * @author: simon-wirtz 6 | */ 7 | fun main(args: Array) { 8 | // val list = (0..100) 9 | // val sub = list.filter { it % 2 == 0 && it <= 50 } 10 | // println("Even numbers from 0 to 50 (${sub.size} Results): \n$sub") 11 | // //Using lambda as argument 12 | // val sub2 = applyToList(list.toList(), { i -> i > 42 }) 13 | // println("Numbers greater 42 with lambda example (${sub2.size} Results): \n$sub2") 14 | // 15 | // 16 | // fun foo(i: Int): Boolean = i > 3 17 | // 18 | // applyToList(list.toList(), ::foo) 19 | // 20 | // //simple Lambda expression 21 | // val sum = { x: Int, y: Int -> x + y } 22 | // println("3 + 10 = ${sum.invoke(3, 10)}") 23 | // println("3 + 10 = ${sum(3, 10)}") 24 | // 25 | // //Lambda accessing its closure (variable in outer scope) 26 | // var completeSum = 0 27 | // list.forEach { 28 | // completeSum += it 29 | // } 30 | // print(completeSum) 31 | 32 | 33 | } 34 | 35 | fun foo(str: String) = str.takeIf { it.isNotBlank() } ?: "empty" 36 | 37 | //Defining function with lambda as parameter 38 | fun applyToList(list: List, func: (T) -> Boolean) = list.filter { it -> func(it) } 39 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/lambda/LambdaWithReceiver.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.lambda 2 | 3 | /** 4 | * Created by simonw on 29.06.17. 5 | */ 6 | 7 | var greet: String.() -> Unit = { println("Hello, my size is $length") } 8 | 9 | fun main(args: Array) { 10 | "Dev".greet() 11 | 12 | println(StringBuilder("Hello ") 13 | .apply { 14 | append("Kotliner") 15 | append("! ") 16 | append("How are you doing?") 17 | }.toString()) 18 | 19 | val message = with(StringBuilder()) { append("This ").append("is a").append(" simple example").toString() } 20 | println(message) 21 | 22 | println(myHigherOrderFun { "The Number is $it" }) 23 | 24 | } 25 | 26 | fun myHigherOrderFun(functionArg: (Int) -> String) = functionArg(5) 27 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/misc/ChecksAndCasts.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.misc 2 | 3 | 4 | /** 5 | * Created on 06.03.2017. 6 | * @author: simon-wirtz 7 | */ 8 | fun main(args: Array) { 9 | checkType("StringX") 10 | 11 | val x = "AnotherString" 12 | // x is automatically cast to string on the right-hand side of `&&` 13 | if (x is String && x.isNotEmpty()) { 14 | print("Automatic cast example result: ${x.length}") // x is automatically cast to String 15 | } 16 | 17 | val anyString: Any = "bla" 18 | //unsafe cast, may throw Exception 19 | val unsafeCastToString: String = anyString as String 20 | //safe cast, may result in null 21 | val safeCastToString: String? = anyString as? String 22 | 23 | } 24 | 25 | /** 26 | * check type at runtime with is and !is 27 | * FYI: Any in Kotlin ~ Object in Java 28 | */ 29 | fun checkType(inst: Any) = when (inst) { 30 | is String -> { 31 | println("String value: $inst") 32 | //Automatic cast by compile after is-check 33 | println("String length: ${inst.length}") 34 | } 35 | is Int -> { 36 | println("Int value: $inst") 37 | //Automatic cast by compile after is-check 38 | println("Int multiplied with 10: ${inst * 10}") 39 | } 40 | else -> println("Any value: $inst") 41 | } 42 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/misc/CollectionFun.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.misc 2 | 3 | /** 4 | * Created on 06.03.2017. 5 | * @author: simon-wirtz 6 | */ 7 | fun main(args: Array) { 8 | //Declare most common collection structures, Kotlin has mutable and immutable collection types 9 | // val list = arrayListOf(1, 2, 3) 10 | // 11 | // 12 | // println("Size of readonly List: ${list.size}") 13 | // println("(First, Last) Element in List: (${list.first()},${list.last()})") 14 | // val set = hashSetOf("a", "b", "c", "d") 15 | // println("Size of Set: ${set.size}") 16 | // val map = hashMapOf(1 to "single", 2 to "many") 17 | // println("Size of Map: ${map.size}") 18 | // 19 | // for ((i, s) in map){ 20 | // println("Entry in map: $i: $s") 21 | // } 22 | 23 | val names = arrayOf("adam", "zack", "eva") 24 | val copy = names.copyOf() 25 | 26 | val sortedArray = copy.sortedArray() 27 | val alphabeticalOrder = names.contentEquals(sortedArray) 28 | println(if (alphabeticalOrder )"Strings are in alphabetical order." else "Strings are not in alphabetical order.") 29 | } 30 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/misc/DataClasses.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.misc 2 | 3 | import org.slf4j.LoggerFactory 4 | 5 | val LOG = LoggerFactory.getLogger(Person::class.java.name) 6 | 7 | /** 8 | * Created on 06.03.2017. 9 | * @author: simon-wirtz 10 | */ 11 | data class Person(val age: Int, val name: String, val country: String = "Germany") { 12 | 13 | init { 14 | LOG.debug("Person created ${this}") 15 | } 16 | 17 | //Mutable property with custom accessor methods using a backing field 18 | var mutableProp: String = "initialValue" 19 | get() { 20 | println("mutableProp get() called") 21 | return field 22 | } 23 | set(value) { 24 | println("mutableProp set('$value') called") 25 | field = value 26 | } 27 | 28 | } 29 | 30 | fun main(args: Array) { 31 | //create new instance, toString equals etc. is overridden 32 | val person = Person(14, "Pete") 33 | LOG.debug("Standard toString(): $person") 34 | // '==' means _structural equality_, whereas '===' means _referential equality_ 35 | LOG.debug("Two different Person instances are structurally equal? ${person == Person(14, "Pete")}") 36 | LOG.debug("Two different Person instances are referentially equal? ${person === Person(14, "Pete")}") 37 | LOG.debug("Two Persons from different countries are structurally equal? ${person == Person(14, "Pete", "Denmark")}") 38 | 39 | 40 | //Destructuring, using componentX functions 41 | val (age, name, city) = person 42 | LOG.debug("$name, $age years of age, from $city") 43 | 44 | println("MutableProp: ${person.mutableProp}") 45 | person.mutableProp = "changed" 46 | println("MutableProp: ${person.mutableProp}") 47 | } 48 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/misc/GroupingFun.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.misc 2 | 3 | 4 | data class TheData( 5 | val b: Int, 6 | val c1: Int, 7 | val c2: Int, 8 | val d1: Int, 9 | val d2: Int 10 | ) 11 | 12 | data class E(val sumC: Int, val sumD: Int) 13 | 14 | fun main(args: Array) { 15 | val alist = listOf(TheData(1, 2, 1, 4, 5), TheData(1, 3, 4, 6, 3), TheData(2, 2, 2, 2, 2), TheData(3, 1, 2, 1, 2)) 16 | val grouped1 = alist.groupBy(TheData::b).mapValues { 17 | E( 18 | it.value.sumBy { it.c1 + it.c2 }, 19 | it.value.sumBy { it.d1 + it.d2 } 20 | ) 21 | } 22 | 23 | val grouped2 = alist.groupingBy(TheData::b).fold(E(0, 0)) { acc, e -> 24 | E(acc.sumC + e.c1 + e.c2, acc.sumD + e.d1 + e.d2) 25 | } 26 | 27 | val grouped3 = alist.groupingBy(TheData::b).aggregate { _, acc: E?, e, _ -> 28 | E((acc?.sumC ?: 0) + e.c1 + e.c2, (acc?.sumD ?: 0) + e.d1 + e.d2) 29 | } 30 | 31 | 32 | grouped3.forEach { 33 | println("Group b=${it.key}: ${it.value}") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/misc/HtmlBuilder.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.misc 2 | 3 | import kotlinx.html.* 4 | import kotlinx.html.dom.create 5 | import org.w3c.dom.Element 6 | import java.io.OutputStream 7 | import java.io.OutputStreamWriter 8 | import javax.xml.parsers.DocumentBuilderFactory 9 | import javax.xml.transform.OutputKeys 10 | import javax.xml.transform.TransformerFactory 11 | import javax.xml.transform.dom.DOMSource 12 | import javax.xml.transform.stream.StreamResult 13 | 14 | fun main(args: Array) { 15 | val document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument() 16 | val html = document.create.html { 17 | head { 18 | title("Hello world") 19 | } 20 | body { 21 | h1("h1Class") { 22 | style = "background-color:red" 23 | +"My header1" 24 | } 25 | p("pClass") { 26 | +"paragraph1" 27 | } 28 | } 29 | } 30 | 31 | html.intoStream(System.out) 32 | } 33 | 34 | fun Element.intoStream(out: OutputStream) { 35 | val dom = DOMSource(this) 36 | with(TransformerFactory.newInstance().newTransformer()) { 37 | setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no") 38 | setOutputProperty(OutputKeys.METHOD, "xml") 39 | setOutputProperty(OutputKeys.INDENT, "yes") 40 | setOutputProperty(OutputKeys.ENCODING, "UTF-8") 41 | setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4") 42 | transform( 43 | dom, StreamResult(OutputStreamWriter(out, "UTF-8")) 44 | ) 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/misc/LoopingFun.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.misc 2 | 3 | 4 | fun main(args: Array) { 5 | for (i in 0..5) { 6 | println("Current: $i") 7 | } 8 | 9 | for (i in 0..10 step 2) { 10 | println("Current: $i") 11 | } 12 | 13 | (0..10 step 2).forEach { println("Current: $it") } 14 | 15 | val range = 3 downTo 1 16 | println(range::class) 17 | for (withIndex in range.withIndex()) { 18 | println("Ranged [${withIndex.index}] = ${withIndex.value}") 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/misc/MarkdownAnalyzer.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.misc 2 | 3 | import java.nio.file.Files 4 | import java.nio.file.Paths 5 | 6 | fun main(args: Array) { 7 | val file = args[0] 8 | Files.lines(Paths.get(file)).forEach { 9 | if (it.startsWith("# ")) { 10 | println(it.replace("# ", "")) 11 | } else if (it.startsWith("##")) { 12 | println(it.replace("#", " ")) 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/misc/NullSafety.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.misc 2 | 3 | /** 4 | * Created on 06.03.2017. 5 | * @author: simon-wirtz 6 | */ 7 | fun main(args: Array) { 8 | val notNullable: String = "abc" 9 | //Compiler Error 10 | //notNullable = null 11 | val nullable: String? 12 | nullable = null 13 | 14 | //Cannot throw NPE 15 | notNullable.length 16 | 17 | //Compiler Error, could throw NPE 18 | //nullable.length 19 | 20 | //Option 1: Works after explicit check 21 | val l = if (nullable != null) nullable.length else -1 22 | 23 | //Option 2: Safe Calls; returns length if not null, 'null' otherwise [useful in chains, will return null if ANY is null: bob?.department?.head?.name ] 24 | println("Length of nullable: ${nullable?.length}") 25 | 26 | 27 | val listWithNulls = listOf("a", "b", null) 28 | for (item in listWithNulls) { 29 | item?.let(::println) // prints A and ignores null 30 | } 31 | 32 | showElvis(nullable) 33 | showElvis("NotNull") 34 | 35 | //Option3: If someone loves NPE you can force it with !! 36 | //nullable!!.length <- this will actually throw a NPE 37 | 38 | } 39 | 40 | //Elvis operator ?: 41 | private fun showElvis(nullable: String?) { 42 | val elvis = nullable?.length ?: -1 43 | println("Elvis operator with '$nullable': $elvis") 44 | } 45 | 46 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/misc/StringsAndRegexFun.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.misc 2 | 3 | /** 4 | * Created by simonw on 17.06.17. 5 | */ 6 | 7 | fun main(args: Array) { 8 | val mod = "ThisIsAString".replaceAfterLast("A", "ManipulatedString") 9 | println(mod) 10 | 11 | val kotlinLogo = """ 12 | .| // 13 | .|// 14 | .|/ \""" 15 | println(kotlinLogo.trimMargin(".")) 16 | 17 | "myString".substring(0..3) 18 | 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/misc/WhenExpressionFun.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.misc 2 | 3 | /** 4 | * Created on 29.05.2017. 5 | * @author: simon-wirtz 6 | */ 7 | enum class Colour { 8 | RED, BLUE, YELLOW, BLACK, ORANGE, GREEN 9 | } 10 | 11 | fun mixColours(col1: Colour, col2: Colour): Colour = 12 | when (setOf(col1, col2)) { 13 | setOf(Colour.RED, Colour.YELLOW) -> Colour.ORANGE 14 | setOf(Colour.BLUE, Colour.YELLOW) -> Colour.GREEN 15 | else -> throw IllegalArgumentException("Colours $col1 & $col2 cannot be mixed!") 16 | } 17 | 18 | 19 | fun main(args: Array) { 20 | fun T.print() = println(this) 21 | 22 | mixColours(Colour.BLUE, Colour.YELLOW).print() 23 | mixColours(Colour.YELLOW, Colour.BLUE).print() 24 | mixColours(Colour.RED, Colour.YELLOW).print() 25 | mixColours(Colour.YELLOW, Colour.RED).print() 26 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/scoping/HttpExample.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.scoping 2 | 3 | import com.google.gson.Gson 4 | import okhttp3.OkHttpClient 5 | import okhttp3.Request 6 | 7 | val ENDPOINT = "https://api.github.com/repos/jetbrains/kotlin/contributors" 8 | 9 | data class Contributor(val login: String, val contributions: Int) 10 | 11 | object GitHubApiCaller { 12 | private val client = OkHttpClient() 13 | 14 | private var cachedLeadResult: Contributor? = null 15 | 16 | fun getKotlinContributor(name: String): Contributor { 17 | if (cachedLeadResult != null) { 18 | println("return cached: $cachedLeadResult") 19 | return cachedLeadResult as Contributor 20 | } 21 | val request = Request.Builder() 22 | .url(ENDPOINT) 23 | .build() 24 | 25 | val response = client.newCall(request).execute() 26 | 27 | 28 | val responseAsString = response.use { 29 | val responseBytes = it.body()?.source()?.readByteArray() 30 | if (responseBytes != null) { 31 | String(responseBytes) 32 | } else throw IllegalStateException("No response from server!") 33 | } 34 | 35 | println("response from git api: $responseAsString\n") 36 | 37 | val contributors = 38 | Gson().fromJson(responseAsString, Array::class.java) 39 | 40 | 41 | val ab = contributors.first { it.login == name } 42 | this.cachedLeadResult = ab 43 | println("found kotlin lead: $ab") 44 | return ab 45 | } 46 | } 47 | 48 | fun main(args: Array) { 49 | GitHubApiCaller.getKotlinContributor("abreslav") 50 | GitHubApiCaller.getKotlinContributor("abreslav") 51 | GitHubApiCallerNextGen.getKotlinContributor("abreslav") 52 | GitHubApiCallerNextGen.getKotlinContributor("abreslav") 53 | } 54 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/scoping/ScopeHttpExample.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.scoping 2 | 3 | import com.google.gson.Gson 4 | import okhttp3.OkHttpClient 5 | import okhttp3.Request 6 | 7 | object GitHubApiCallerNextGen { 8 | private val client = OkHttpClient() 9 | private var cachedLeadResult: Contributor? = null 10 | 11 | fun getKotlinContributor(name: String): Contributor { 12 | if (cachedLeadResult != null) { 13 | println("return cached: $cachedLeadResult") 14 | return cachedLeadResult as Contributor 15 | } 16 | 17 | val contributors = with(client) { 18 | val request = Request.Builder().url(ENDPOINT).build() 19 | val response = request.let { 20 | newCall(it).execute().use { 21 | it.body()?.source()?.readByteArray()?.let { String(it) } 22 | ?: throw IllegalStateException("No response from server!") 23 | } 24 | } 25 | response.let { 26 | println("response from git api: $it\n") 27 | Gson().fromJson(it, Array::class.java) 28 | } 29 | 30 | } 31 | 32 | return contributors.first { it.login == name }.also { 33 | this.cachedLeadResult = it 34 | println("found kotlin lead: $it") 35 | } 36 | 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/scoping/ScopePresentationAlso.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.scoping 2 | 3 | //run1 4 | fun notUsingReceiver(text: String?): Int { 5 | return 1234.also { println("the function did its job!") } 6 | } 7 | 8 | class Bar(var foo: String? = null) 9 | class BazBar(private var bazInit: () -> String) { 10 | private lateinit var baz: String 11 | 12 | fun getThatBaz() = bazInit().also { baz = it } 13 | } 14 | 15 | //run2 16 | fun initAlsoAssign() { 17 | val bar: Bar = Bar().also { 18 | it.foo = "another value" 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/scoping/ScopePresentationApply.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.scoping 2 | 3 | fun initApply() { 4 | val bar: Bar = Bar().apply { 5 | foo = "another value" 6 | } 7 | } 8 | 9 | class FooBar(var a: Int = 0, var b: String? = null) { 10 | fun first(aArg: Int) = apply { a = aArg } 11 | fun second(bArg: String) = apply { b = bArg } 12 | } 13 | 14 | 15 | fun main(args: Array) { 16 | FooBar().first(10).second("foobarValue") 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/scoping/ScopePresentationLet.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.scoping 2 | 3 | //let1 4 | fun getLength(text: String?): Int { 5 | val len = text?.let { 6 | println("get length of $it") 7 | it.length 8 | } ?: 0 9 | return len 10 | } 11 | 12 | //let2 13 | fun confinedVariable(): String { 14 | val transform = "stringConfinedToLetScope".let { 15 | println("variable can be accessed in let: $it") 16 | "$it${it.length}" 17 | } 18 | //cannot access original string from here 19 | return transform 20 | } 21 | 22 | fun main(args: Array) { 23 | println(confinedVariable()) 24 | } 25 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/scoping/ScopePresentationRun.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.scoping 2 | 3 | import java.util.* 4 | 5 | //run1 6 | fun getLengthWithRun(text: String?): Int { 7 | return text?.run { 8 | println("get length of $this") 9 | length //this can be omitted 10 | } ?: 0 11 | } 12 | 13 | //run2 14 | fun run2() { 15 | val date: Int = Calendar.getInstance().run { 16 | set(Calendar.YEAR, 2030) 17 | get(Calendar.DAY_OF_YEAR) 18 | } 19 | 20 | } 21 | 22 | fun main(args: Array) { 23 | println(confinedVariable()) 24 | } 25 | -------------------------------------------------------------------------------- /src/main/kotlin/de/swirtz/kotlin/scoping/ScopePresentationWith.kt: -------------------------------------------------------------------------------- 1 | package de.swirtz.kotlin.scoping 2 | 3 | import java.util.* 4 | 5 | fun initWith() { 6 | val s: String = with(StringBuilder("init")) { 7 | append("some").append("thing") 8 | println("current value: $this") 9 | toString() 10 | } 11 | } 12 | 13 | object Foo { 14 | fun ClosedRange.random() = 15 | Random().nextInt(endInclusive - start) + start 16 | } 17 | 18 | 19 | fun main(args: Array) { 20 | val s = createString { 21 | append(4) 22 | append("hello") 23 | } 24 | 25 | } 26 | 27 | fun createString(block: StringBuilder.() -> Unit): String { 28 | val sb = StringBuilder().block() 29 | return sb.toString() 30 | } -------------------------------------------------------------------------------- /src/main/resources/test.txt: -------------------------------------------------------------------------------- 1 | some content --------------------------------------------------------------------------------