Dart private property - dart

Some said that private properties can be used to change class definition without changing existing codes depending on the class before.
For example;
main() {
var p1 = new Project();
p1.name = 'Breeding';
p1.description = 'Managing the breeding of animals';
print('$p1');
// prints: Project name: Breeding - Managing the breeding of animals
}
class Project {
String name, description;
toString() => 'Project name: $name - $description';
}
Now, class Project is changed as below using private variables.
main() {
var p1 = new Project();
p1.name = 'Breeding';
p1.description = 'Managing the breeding of animals';
print('$p1');
// prints: Project name: BREEDING - Managing the breeding of animals
var p2 = new Project();
p2.name = 'Project Breeding of all kinds of animals';
print("We don't get here anymore because of the exception!");
}
class Project {
String _name; // private variable
String description;
String get name => _name == null ? "" : _name.toUpperCase();
set name(String prName) {
if (prName.length > 20)
throw 'Only 20 characters or less in project name';
_name = prName;
}
toString() => 'Project name: $name - $description';
}
What does it mean that;
(due to the private properties introduced) The code that already existed in main (or in general, the client code that uses this property) does not need to change
The author of the above codes(Learning Dart) said that, due to the newly inserted private property(_name), the existing codes like 'main()' are NOT affected by the change of properties in the Project class.
That's what I can't understand. How newly inserted private properties in existing classes can be a way to keep other codes depending on those classes untouched or safe?

I still don't know what your actual question is.
You can use private fields, classes and functions/methods to reorganize (refactor) your code and
as long as the public API is not affected and the users of the library do not depend on the internal behavior of the classes the users should not recognize the change.
Privacy is mostly a communication medium to indicate that some members (public) are intended to be accessed by API users and private members are an implementation detail the API user should not care about.
Don't confuse privacy with security. Reflection usually allows access to private members.
If this is not the answer you were looking for please add a comment or improve your question.

Related

Modifying the DTO name appearing in OpenAPI (Swagger) schemas in NestJS

I am facing a problem where my DTO types are named one thing, but I want them to appear with a different name in the OpenAPI doc page.
For example, I have a UserDto class that I use in my controller, but wanted it to appear as simply "User" in the schemas section (and everywhere else this applies). Is that possible? Is there any decorator I can use?
I know I can simply modify the class name, but there is already a different user class used elsewhere.
I have searched everywhere with no avail.
BTW, I am using typescript and nestjs.
Every help will be appreciated, thanks!
Out of the box, Nest.js doesn't yet offer a ready-made solution. There is an open pull request (as mentioned earlier) https://github.com/nestjs/swagger/pull/983, but when it will be merged is unknown.
You can change the DTO name in schemas using one of the following approaches:
Add a static name property to your DTO.
class UserDto {
static name = 'User'; // <- here
#ApiProperty()
firstName: string;
// ...
}
But in strict mode, TypeScript will show an error like:
Static property 'name' conflicts with built-in property 'Function.name' of constructor function 'UserDto'.
Write a decorator with an interface as suggested in the pull request and use it until the desired functionality appears in Nest.js.
The decorator adds the name property with the needed value to the wrapper class for the DTO.
type Constructor<T = object> = new(...args: any[]) => T;
type Wrapper<T = object> = { new(): (T & any), prototype: T };
type DecoratorOptions = { name: string };
type ApiSchemaDecorator = <T extends Constructor>(options: DecoratorOptions) => (constructor: T) => Wrapper<T>;
const ApiSchema: ApiSchemaDecorator = ({ name }) => {
return (constructor) => {
const wrapper = class extends constructor { };
Object.defineProperty(wrapper, 'name', {
value: name,
writable: false,
});
return wrapper;
}
}
Use as suggested in the proposal:
#ApiSchema({ name: 'User' }) // <- here
class UserDto {
#ApiProperty()
firstName: string;
// ...
}
And don't forget that in TypeScript 5 the decorator API will change to something close to the implementation in JavaScript 😉
I solved in my case using #ApiModel
like this
#ApiModel(value="MeuLindoDto")
public class NameOriginalClassResponseDto ...

How to clone (copy values) a complex object in Dart 2

I would like to clone a complex object (copy values), not referencing, using Dart 2.
Example:
class Person {
String name;
String surname;
City city;
}
class City {
String name;
String state;
}
main List<String> args {
City c1 = new City()..name = 'Blum'..state = 'SC';
Person p1 = new Person()..name = 'John'..surname = 'Xuebl'..city = c1;
Person p2 = // HERE, to clone/copy values... Something similar to p1.clone();
}
What would be the way (best practice) to do this?
Update note: This How can I clone an Object (deep copy) in Dart? was posted some time ago. The focus here is to understand if Dart 2 that is bringing many improvements, has a facility for copying complex objects.
With the classes you have shown us here, there is nothing shorter than
Person p2 = Person()
..name = p1.name
..surname = p1.surname
..city = (City()..name = p1.city.name..state = p1.city.state);
If you add a clone method to Person and City, then you can obviously use that.
There is nothing built in to the language to allow you to copy the state of an object.
I would recommend changing the classes, at least by adding a constructor:
class Person {
String name;
String surname;
City city;
Person(this.name, this.surname, this.city);
}
class City {
String name;
String state;
City(this.name, this.state);
}
Then you can clone by just writing:
Person P2 = Person(p1.name, p1.surname, City(p1.city.name, p1.city.state));
(And ob-link about names)
I say that there is no language feature to copy objects, but there actually is, if you have access to the dart:isolate library: Sending the object over a isolate communication port. I cannot recommend using that feature, but it's here for completeness:
import "dart:isolate";
Future<T> clone<T>(T object) {
var c = Completer<T>();
var port = RawReceivePort();
port.handler = (Object o) {
port.close();
c.complete(o);
}
return c.future;
}
Again, I cannot recommend using this approach.
It would work for simple objects like this, but it doesn't work for all objects (not all objects can be sent over a communication port, e.g., first-class functions or any object containing a first class function).
Write your classes to support the operations you need on them, that includes copying.
My simpler solution just let clone() return a new Person with the current values:
class Person {
String name;
String surname;
City city;
Person(this.name, this.surname, this.city);
clone() => Person(name, surname, city);
}
You might further need to recursively clone the objects in your Person. as an example by creating a similar clone() function in the City and using it here as city.clone().
For the strings you will need to check their behavior or also create / add a way for cleaning them.
As said, there is no built in solution for that, but if the ideia is to accomplish immutable value types you can check built_value.
https://medium.com/dartlang/darts-built-value-for-immutable-object-models-83e2497922d4
I noted that using Map.from() do a shallow copy and not a deep copy.
To do a deep copy of a class containing a Map of anoter Class, one solution can be to use a nammed constructor
class MyClassB {
int myVar;
// Constructor
MyClassB(this.id);
// Named Constructor to do a deep clone
MyClassB.clone(MyClassB b){
id = b.id;
}
}
class MyClassA {
Map<int,MyClassB> mapOfClassB;
// Constructor
MyClassA(this.myClassB)
// Named constructor to do a deep clone
MyClassA.clone(MyClassA a){
Map<int,myClassB> m = {};
myClassB = a.mapOfClassB.forEach((k,v)=> m[k] = MyClassB.clone(v)); // Use the clone constructor here, if not the maps in MyClassA and MyClassB will be linked
}
}
main() {
var b1 = MyClassB(20);
var a1 = MyClassA({0:b1});
var a2 = MyClass1A.clone(a1);
a2.mapOfClassB[0].id = 50;
print(a1.mapOfClassB[0].id); // Should display 20
print(a2.(a1.mapOfClassB[0].id) // Should display 50
}
Using a package like freezed, you could make deep copies of the complex objects.
Although one downside is that the objects are immutable and you cannot make shallow copies of it. But again, it depends on your use case and how you want your objects to be.

FLUTTER How to get variable based on passed string name?

I have stored variables in a class with their code names.
Suppose I want to get XVG from that class, I want to do
String getIconsURL(String symbol) {
var list = new URLsList();
//symbol = 'XVG'
return list.(symbol);
}
class URLsList{
var XVG = 'some url';
var BTC = 'some url';
}
Can someone help me achieve this or provide me with a better solution?
Dart when used in flutter doesn't support reflection.
If it's text that you want to have directly in your code for some reason, I'd advise using a text replace (using your favourite tool or using intellij's find + replace with regex) to change it into a map, i.e.
final Map<String, String> whee = {
'XVG': 'url 1',
'BTC': 'url 2',
};
Another alternative is saving it as a JSON file in your assets, and then loading it and reading it when the app opens, or even downloading it from a server on first run / when needed (in case the URLs need updating more often than you plan on updating the app). Hardcoding a bunch of data like that isn't necessarily always a good idea.
EDIT: how to use.
final Map<String, String> whee = .....
String getIconsURL(String symbol) {
//symbol = 'XVG'
return whee[symbol];
}
If you define it in a class make sure you set it to static as well so it doesn't make another each time the class is instantiated.
Also, if you want to iterate through them you have the option of using entries, keys, or values - see the Map Class documentation
I'd just implement a getProperty(String name) method or the [] operator like:
class URLsList{
var XVG = 'some url';
var BTC = 'some url';
String get operator [](String key) {
switch(key) {
case 'XVG': return XVG;
case 'BTC': return BTC;
}
}
}
String getIconsURL(String symbol) {
var list = new URLsList();
return list[symbol];
}
You can also use reflectable package that enables you to use reflection-like code by code generation.
Assuming that the class is being created from a JSON Object, you can always use objectName.toJSON() and then use the variable names are array indices to do your computations.

Cannot access domain property from Java class (in src folder)

I cannot access exploits property in domain class - Scenario , from my java class - MatchScenario , located in Grails src folder.
Already tried :
Explicit methods :
I have tried explicitly creating the get;set; but I get stackOverflow error since the setExploits() is called infinitely by itself for some reason.
Service to return the exploit field,
Though the service was created, it's never called on my fork-debug integration testing, so tests hangs with no exception
compilation error ->
Error:(59, 44) java: cannot find symbol
symbol: variable exploits
location: variable scenario of type core.Scenario
Java class, error on the inner loop ->
public class MatchScenario implements Callable{
private static final Logger LOG = Logger.getLogger(MatchScenario.class.getCanonicalName());
private List<Scenario> scenarioList
#Override
public List<Scenario> call() throws Exception {
LOG.debug( "*********************** schedule matcher called *****************************" );
if (scenarioList==null) {
LOG.debug("scenarioList not initialized ");
return null;
}
List<Scenario> scenarioAvailable = new ArrayList<Scenario>();
for (Scenario scenario : scenarioList){
for (Exploit exploit : scenario.exploits){
//println 'exploit -> '+exploit
if (!match( exploit.getExpression() ) ){
break;
}
}
//happens only when all scenario are available ( no break issued )
scenarioAvailable.add(scenario);
}
return scenarioAvailable;
}
private boolean match(String expression) {
return true;
}
}
Scenario domain object ->
package core
class Scenario {
String name
static belongsTo = [ Exploit ]
static hasMany = [ exploits : Exploit ]
static constraints = {
name nullable: false , maxSize: 32
}
}
You're confusing fields and properties. When you declare a property in a Groovy class, e.g. String name, the Groovy compiler converts that to a private field and adds a getter and a setter (unless you already defined one or both of them - it won't overwrite), in this case something like
private String name
public void setName(String name) { this.name = name }
public String getName() { return name }
It only does this if there's no scope modifier, so public String name and protected String name would both stay as defined.
One benefit of this is that you can later add logic to the getter and/or setter to modify the value, do some validation checks or computations, etc., and in Groovy you would still read and write to the name property since property access always calls the underlying setters and getters, and since properties like this are a Groovy-only thing that Java can't access, you would have been calling the setter and getter from Java all along, so you wouldn't need to recompile the Java classes that used the class.
Declaring a hasMany like yours creates an exploits property, effectively
Set<Exploit> exploits
and that property (added by a Grails AST transformation) is likewise converted to a private field with a getter and setter. So to get this working from Java, use the getter:
for (Exploit exploit : scenario.getExploits()) {

mapping a one-to-many where the map key is an int

I am trying to understand the annotations MapKey and MapKeyColumn and I have found them confusing. I was reading an article that made me even more confused (The specification section)
I have an entity with an int field and it is not the primary key:
public class Connections{
...
public final int getConnectionId() {
return this.connectionId;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "FK_StartpointTNA")
public final Endpoint getStartpoint() {
return this.startpoint;
}
...
}
and in the other side I have
public class Endpoint{
...
#OneToMany(mappedBy = "startpoint", fetch = FetchType.LAZY, cascade = { javax.persistence.CascadeType.REMOVE })
#MapKeyColumn(name = "connectionId")
public Map<Integer, Connections> getConnections() {
return this.connections;
}
....
}
I dont know really how to fix this. I keep getting: org.apache.openjpa.persistence.ArgumentException: "connections" declared that it is mapped by "startpoint", but that is a not a field of the related type.
what is the proper way to map this?
As someone posted to the JIRA you opened, get rid of the final on your methods.
From the JPA 2 spec:
(Section 2.1 "The Entity Class", page 21) states: "The entity class must not be final. No methods or persistent instance variables of the entity class may be final."
I had the same issue and getting the same error-message
but in my case I was wrong with
mappedBy = "foo"
where foo must declare the field! Not the column.

Resources