Play 2.X ScalaRouting Boolean Parameter - scala

How can I use boolean in route definition?
If I use this way,
GET /user/:userName controllers.AppController.user(userName, registerDone:Boolean?=0)
it throws this error:
[error] found : Int(0)
[error] required: Boolean
If I use this way,
GET /user/:userName controllers.AppController.user(userName, registerDone:Boolean?=false)
it throws this error:
bad request at: /user/aajjblack?registerDone=true, Cannot parse
parameter registerDone as Boolean: should be 0 or 1
Controller:
public static Result user(final String userName, Boolean registerDone) {
}

Use... Int instead
GET /user/:userName controllers.AppController.user(userName, registerDone: Int?=0)
action:
public static Result user(final String userName, int registerDone) {
if(registerDone == 0){
return badRequest();
}
// do something with registered user...
return ok();
}
It's simplest replace of any kind of booleans, as you can just check if registerDone is bigger than 0 (and it still keeps type-safety).

Related

Avoid duplication of null type checking in Dart

My current goal is to remove this code duplication:
final int? myNullableInt = 10;
/// Everywhere I need to do this null verification:
if (myNullableInt == null) return null;
return someOtherMethodThatReceivesANonNullableInt(myNullableInt);
I want to convert to something like we have in Kotlin:
final int? myNullableInt = 10;
return myNullableInt?.apply((myInt) => someOtherMethodThatReceivesANonNullableInt(myInt));
I did it:
extension ApplyIfNotNull on Object? {
T? apply<T extends Object?>(Object? obj, T? Function(Object) fn) {
if (obj == null) return null;
return fn(obj);
}
}
But this gives me a static error:
The argument type 'Object' can't be assigned to the parameter type 'int'.
Note: this should work with all types, e.g ints, Strings, double and MyOwnClassTypes.
Is there something I can do? or am I missing something?
extension ApplyIfNotNull on Object? {
T? apply<T extends Object?>(Object? obj, T? Function(Object) fn) {
if (obj == null) return null;
return fn(obj);
}
}
That doesn't work because it declares that the callback be capable of accepting any Object argument, but you're presumably trying to use it with a function that accepts only an int argument. It's also unclear why you've made an extension method since it doesn't involve the receiver (this) at all.
You need to make your function generic on the callback's argument type as well:
R? applyIfNotNull<R, T>(T? obj, R Function(T) f) =>
(obj == null) ? null : f(obj);
(That's the same as what I suggested in https://github.com/dart-lang/language/issues/360#issuecomment-502423488 but with the arguments reversed.)
Or, as an extension method, so that it can work on this instead of having the extra obj argument:
extension ApplyIfNotNull<T> on T? {
R? apply<R>(R Function(T) f) {
// Local variable to allow automatic type promotion. Also see:
// <https://github.com/dart-lang/language/issues/1397>
var self = this;
return (self == null) ? null : f(self);
}
}
Also see https://github.com/dart-lang/language/issues/360 for the existing language feature request and for some other suggested workarounds in the meantime.

Dart : Read annotated value of a field

I have a Dart enum which looks like this:
enum Gender {
#JsonValue(0)
male,
#JsonValue(1)
female,
}
I have created a dart extension that returns the String name and int value. It looks something like this -
extension GenderExtention on Gender {
String get name {
switch (this) {
default:
return _getDefaultName(this);
}
}
//For the enum male, it returns "Male"
String _getDefaultName(Community value) {
if (value == null) {
return null;
}
String valueStr = value.toString();
String enumName = valueStr.substring(valueStr.indexOf('.') + 1);
return enumName[0].toUpperCase() + enumName.substring(1);
}
int get value {
switch (this) {
case Gender.male:
return 0;
case Gender.female:
return 1;
default:
return null;
}
}
}
This becomes painful for larger enums, especially the value section.
Are there any suggestions on how to get the enum value (0 for #JsonValue(0)) more easily than manually defining it in the extension? Would using something like reflections help here?
the only way to access annotations at run-time is indeed reflection using dart:mirrors. That library is not available when compiling to the web or for Flutter, so it's probably not going to solve your problem.
What you can do here is:
int get value => this.index;
That only works if the values are actually the same as the index (0 for the first declared value, 1 for the next, etc.)

Can not call value of non function type

I am getting error can not call value of non function type. Whats wrong in this ?
extension FileModel {
var isPlayableMedia: Bool {
get {
return isPlayableMedia(mediaType: mediaType)
}
}
func isPlayableMedia(_ mediaType: MediaType) -> Bool {
return mediaType == MediaType.image || mediaType == MediaType.video
}
}
Either remove the label parameter when the method is called
var isPlayableMedia: Bool {
return isPlayableMedia(mediaType) // assuming `mediaType` is declared somewhere else.
}
Or specify the label parameter in the declaration (remove the underscore)
func isPlayableMedia(mediaType: MediaType) -> Bool {
return mediaType == MediaType.image || mediaType == MediaType.video
}
Nothing much just check your function signature and use it in right way.
replace your var with the following code :
var isPlayableMedia: Bool {
get {
return isPlayableMedia(mediaType)
}
}
OR
just remove the argument label from you method calling

Compiler error when using function in lazy stored property

I am getting an error that says "Cannot convert value of type 'String' to argument type 'Test'" when trying to return a value from a function in lazy stored property. I am not able to spot any issue in the lazy var's closure.
import UIKit
public struct Value {}
public class Test {
var id: String = ""
public func getValueById(id: String) -> Value {
return Value()
}
public lazy var value: Value = {
// Compiler error: Cannot convert value of 'String' to expected argument type 'Test'
return getValueById(self.id)
}()
}
The compiler is confused about getValueById and the error message is meaningless - if not misleading.
What you need is to add self in front of getValueById(self.id) inside the closure:
public struct Value {}
public class Test {
var id: String = ""
public func getValueById(id: String) -> Value {
return Value()
}
public lazy var value: Value = {
return self.getValueById(self.id)
}()
}

Implement your own object binder for Route parameter of some object type in Play scala

Well, I want to replace my String param from the following Play scala Route into my own object, say "MyObject"
From GET /api/:id controllers.MyController.get(id: String)
To GET /api/:id controllers.MyController.get(id: MyOwnObject)
Any idea on how to do this would be appreciated.
Well, I have written up my own "MyOwnObject" binder now. Another way of implementing PathBindable to bind an object.
object Binders {
implicit def pathBinder(implicit intBinder: PathBindable[String]) = new PathBindable[MyOwnObject] {
override def bind(key: String, value: String): Either[String, MyOwnObject] = {
for {
id <- intBinder.bind(key, value).right
} yield UniqueId(id)
}
override def unbind(key: String, id: UniqueId): String = {
intBinder.unbind(key, id.value)
}
}
}
Use PathBindable to bind parameters from path rather than from query. Sample implementation for binding ids from path separated by comma (no error handling):
public class CommaSeparatedIds implements PathBindable<CommaSeparatedIds> {
private List<Long> id;
#Override
public IdBinder bind(String key, String txt) {
if ("id".equals(key)) {
String[] split = txt.split(",");
id = new ArrayList<>(split.length + 1);
for (String s : split) {
long parseLong = Long.parseLong(s);
id.add(Long.valueOf(parseLong));
}
return this;
}
return null;
}
...
}
Sample path:
/data/entity/1,2,3,4
Sample routes entry:
GET /data/entity/:id controllers.EntityController.process(id: CommaSeparatedIds)
I'm not sure if it works for binding data in the path part of a URL, but you may want to read the docs on QueryStringBindable if you're able to accept your data as query params.