Dart - assigning class to factory constructor - dart

I have found an interesting (to me) place in Dart code:
factory Uri(
{String scheme,
String userInfo,
String host,
int port,
String path,
Iterable<String> pathSegments,
String query,
Map<String, dynamic /*String|Iterable<String>*/ > queryParameters,
String fragment}) = _Uri; // <==== here
and then:
class _Uri implements Uri {
...
}
It looks like the class _Uri is assigned to the factory constructor. I don't think I have read about it in the language tour or anywhere else. What is this 'technique' called? How does it work? Are there any special requirements for the factory constructor and the class for this to work?

Related

Why use factory when constructing a new instance from a map structure?

I'm trying to really understand the flow of JSON data coming from an API until I can consume it as an object.
Now I think I have everything in place, my only question is why I see some people use the factory when they use the named constructor .fromJson.
According to the Dart documentation:
we use the factory keyword when we implement a constructor that
doesn't always create a new instance of your class.
But in this case, we always will make an instance when using fromJson, right?
Then why some people use:
factory User.fromJson(Map<String, dynamic> json) =>
User(name: json['name'], alias: json['alias']);
instead of the more reasonable:
User.fromJson(Map<String, dynamic> json)
: name = json['name'],
alias = json['alias'];
Thanks so much for any aclaration.
Let me add some examples to lrn's helpful explanation.
Say you create a User class like so:
class User {
User({this.name, this.alias});
User.fromJson(Map<String, dynamic> json) {
return User(name: json['name'], alias: json['alias']);
}
final String name;
final String alias;
}
The User.fromJson constructor is a generative constructor. One characteristic of generative constructors is that you can forward to them from another constructor. That means someone else can subclass your class like so:
class SoftwareUser extends User {
SoftwareUser(Map<String, dynamic> json) : super.fromJson(json);
}
The super.fromJson(json) part just forwards the parameter to your original constructor. So far so good.
But later you decide that you'd like to do a bit of error checking and text manipulation on that JSON map before you try to create an object from it. You can do a little with asserts but you're limited. Factory constructors, on the other hand, would allow you to do a lot more. Here's an example of doing a more work in the constructor:
class User {
User({this.name, this.alias});
factory User.fromJson(Map<String, dynamic> json) {
String userName = json['name'];
String userAlias = json['alias'];
if (userName == null || userAlias == null) throw FormatException();
userName = userName.toUpperCase();
userAlias = userAlias.toUpperCase();
return User(name: userName, alias: userAlias);
}
final String name;
final String alias;
}
That's great for the User class, but the problem is that now the SoftwareUser subclass is broken.
class SoftwareUser extends User {
SoftwareUser(Map<String, dynamic> json) : super.fromJson(json); // <-- error
}
// The constructor 'User User.fromJson(Map<String, dynamic> json)'
// is a factory constructor, but must be a generative constructor
// to be a valid superinitializer.
//
// Try calling a different constructor of the superclass, or making
// the called constructor not be a factory constructor.
As the error message says, you can't forward to a factory constructor.
If you had started with the factory constructor for User in the beginning, then the SoftwareUser subclass would never have been able to forward like that. The factory constructor would allow you to change from this:
factory User.fromJson(Map<String, dynamic> json) =>
User(name: json['name'], alias: json['alias']);
to this:
factory User.fromJson(Map<String, dynamic> json) {
String userName = json['name'];
String userAlias = json['alias'];
if (userName == null || userAlias == null) throw FormatException();
userName = userName.toUpperCase();
userAlias = userAlias.toUpperCase();
return User(name: userName, alias: userAlias);
}
without breaking any subclasses. That's why lrn called it defensive design. Even though you don't know your future needs, you'll be able to make internal changes to how the object is created later without breaking external dependencies.
Making a public constructor a factory can be a defensive design, even when it's not technically required.
If you make a constructor generative, then someone, somewhere, might extend your class with a subclass and forward their constructor to your generative constructor.
At that point, it becomes a breaking change to make your constructor into a factory. If you decide you want more validation and it becomes more convenient if the constructor was a factory, you're now blocked from making the change.
Making a public constructor generative is a promise (so is making it const), so you're better of not doing it unless you actually want to. Don't expose public generative (or const) constructors by accident, or just because you can. Do it if you intend the class to be used as a super-class through that constructor. Otherwise it's safer to expose only a factory constructor, and keep the generative constructor private.

Constructors can't have type parameters.dart(type_parameter_on_constructor)

I am using the following dart packages (json_annotation, json_serializable, build_runner) to serialize/de-serialize json according to this page.
This is my code:
import 'package:json_annotation/json_annotation.dart';
part 'car_type.g.dart';
#JsonSerializable()
class CarType {
final int id;
#JsonKey(name: 'type_label')
final String label;
final String description;
CarType(this.id, this.label, this.description);
factory CarType.fromJson(Map<String, dynamic> json) =>
_$CarTypeFromJson(json);
factory List<CarType> CarType.fromJsonList(dynamic jsonArray){
final list = jsonArray as List;
final carTypesList = list.map((i) => CarType.fromJson(i));
return carTypesList;
}
}
So with the factory List<CarType> CarType.fromJsonList(dynamic jsonArray) I want to pass a json array to get back a list of CarType objects. However I'am getting a couple of compiler errors namely:
This function has a return type of 'List', but doesn't end with a return statement.dart(missing_return)
The default constructor is already defined.dart(duplicate_constructor_default)
Constructors can't have type parameters.dart(type_parameter_on_constructor)
Any idea what is going on?
factory List<CarType> CarType.fromJsonList(dynamic jsonArray){
You can't specify a return type for a constructor.
The return type is always the same as the class the constructor is member of.
Just replace factory with static and you should be fine,
except json_serializable expects a factory constructor, then you need to remove the return type and find another approach to get the List.

How Can a Class Member Value From a GebSpec Base Class

I'm currently trying to create a GlobalExtension for my Geb-Spock framework. So far here is my extension:
class OnFailureListener extends AbstractRunListener {
private final String id
private final SauceREST sauceREST
public OnFailureListener(String id, String username, String accessKey) {
this.id = id
this.sauceREST = new SauceREST(username, accessKey)
}
def void error(ErrorInfo error) {
println error;
this.sauceREST.updateJobInfo(this.sessionIdProvider.getSessionId(), "failed")
}
}
class ResultExtension extends AbstractGlobalExtension {
protected final String username = System.getenv("SAUCE_USERNAME")
protected final String accesskey = System.getenv("SAUCE_ACCESS_KEY")
protected final String sessionId
#Override
void visitSpec(SpecInfo specInfo) {
specInfo.addListener(new OnFailureListener(sessionId, username, accesskey))
}
}
My issue is that the sesssionId value gets assigned in the GebSpec base class I'm using for other specs, and cannot be assigned directly in the extension class. Beyond using some gnarly reflection approaches, is there a way to access the sessionId value assigned in the base class in the extension? I'd also like to avoid using an AnnotationExtension since I'd like to apply this globally without modifying any spec code (similar to a JUnit TestWatcher pattern).
The easiest way for you would be to write the sessionId into a shared ThreadLocal that can be accessed by your listener and the spec, otherwise you'll have to implement an org.spockframework.runtime.extension.IMethodInterceptor so that you can gain access to the actual test instance to extract the field value.

Different variable name from querystring

My controller has an object as parameter
Function Search(ByVal model As ItemSearchModel) As ActionResult
Which look something like this
Public Class ItemSearchModel
Public Property SearchQuery As String
And, as you can imagine, the url will look this like
/Search?SearchQuery=test
I want to change the query string to have a small variable, sort of like
/Search?s=test
Is there a built-in way I could keep the same variable name in my class? Something like
Public Class ItemSearchModel
<QueryString(Name:="s")> _
Public Property SearchQuery As String
I think you can use the ActionParameterAlias package from Nuget to accomplish what you want.
You can define two properties, both pointing to the same field. Then you can access that item using either s or SearchQuery from the URL.
Public Class ItemSearchModel
Private _s As String
Public Property s() As String
Get
Return _s
End Get
Set(value As String)
_s = value
End Set
End Property
Public Property SearchQuery() As String
Get
Return _s
End Get
Set(value As String)
_s = value
End Set
End Property
End Class

How to bind String to variable in Guice?

I'm new to Guice and here is a naive question. I learned that we could bind String to a particular value through:
bind(String.class)
.annotatedWith(Names.named("JDBC URL"))
.toInstance("jdbc:mysql://localhost/pizza");
But what if I want to bind String to any possible characters?
Or I think it could be described this way:
How can I replace "new SomeClass(String strParameter)" with Guice?
You first need to annotate the constructor for SomeClass:
class SomeClass {
#Inject
SomeClass(#Named("JDBC URL") String jdbcUrl) {
this.jdbcUrl = jdbcUrl;
}
}
I prefer to use custom annotations, like this:
class SomeClass {
#Inject
SomeClass(#JdbcUrl String jdbcUrl) {
this.jdbcUrl = jdbcUrl;
}
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.PARAMETER})
#BindingAnnotation
public #interface JdbcUrl {}
}
Then you need to provide a binding in your Module:
public class SomeModule extends AbstractModule {
private final String jdbcUrl; // set in constructor
protected void configure() {
bindConstant().annotatedWith(SomeClass.JdbcUrl.class).to(jdbcUrl);
}
}
Then an time Guice creates SomeClass, it will inject the parameter. For instance, if SomeOtherClass depends on SomeClass:
class SomeOtherClass {
#Inject
SomeOtherClass(SomeClass someClass) {
this.someClass = someClass;
}
Often, when you think you want to inject a String, you want to inject an object. For instance, if the String is a URL, I often inject a URI with a binding annotation.
This all assumes there is some constant value you can define at module creation time for the String. If the value isn't available at module creation time, you can use AssistedInject.
This might be off-topic, but Guice makes configuration much easier than writing an explicit binding for every String you need. You can just have a config file for them:
Properties configProps = Properties.load(getClass().getClassLoader().getResourceAsStream("myconfig.properties");
Names.bindProperties(binder(), configProps);
and voilĂ  all your config is ready for injection:
#Provides // use this to have nice creation methods in modules
public Connection getDBConnection(#Named("dbConnection") String connectionStr,
#Named("dbUser") String user,
#Named("dbPw") String pw,) {
return DriverManager.getConnection(connectionStr, user, pw);
}
Now just create your Java properties file myconfig.properties at the root of your classpath with
dbConnection = jdbc:mysql://localhost/test
dbUser = username
dbPw = password
or merge authorization information from some other source into the properties and you're set.
I was able to inject a string through Named annotation.
#Provides
#Named("stage")
String stage() {
return domain;
}
class SomeClass {
#Inject
#Named("stage")
String stageName;
}
I find a solution in the FAQ of Guice:
http://code.google.com/docreader/#p=google-guice&s=google-guice&t=FrequentlyAskedQuestions
In addition to define an annotation and a String attribute in MyModule, I need to write below line to get a instance of SomeClass:
SomeClass instance = Guice.createInjector(new MyModule("any string i like to use")).getInstance(SomeClass.class);
But I remembered that Injector.getInstance() should not be used except for the root object, so is there any better way to do this?

Resources