Why can I use reflection to call private methods of an external class? - dart

I can use reflection to access and call private methods of a class outside of my library. Is this a bug or desired behaviour? If it's desired, how can I make it impossible for external code to access private members/methods?
library left;
class Thing {
void _priv(String s) {
print(s);
}
}
library right;
void main() {
var t = new Thing();
var mirror = reflect(t);
mirror.type.declarations.values
.where( (d) => d.isPrivate && d is MethodMirror )
.forEach( (d) {
print(d.simpleName == #_priv); // prints false
mirror.getField(d.simpleName).reflectee("Hello World"); // prints Hello World
});
}

This privacy is not a security feature, is's only to communicate to users of your API that such a method is intended for internal usage only. Access using mirrors can't be prevented.
Disallowing it in mirrors wouldn't prevent access because the VM and dart2js just mangle or prefix private method names to prevent name collisions with public methods. These names can be predicted or found using brute force and then be called.

Calling private methods are mostly useful in writing the DSL(Domain Specific Language)s.

Related

How can I inject with Guice my api into dataflow jobs without needed to be serializable?

This question is a follow on after such a great answer Is there a way to upload jars for a dataflow job so we don't have to serialize everything?
This made me realize 'ok, what I want is injection with no serialization so that I can mock and test'.
Our current method requires our apis/mocks to be serialiable BUT THEN, I have to put static fields in the mock because it gets serialized and deserialized creating a new instance that dataflow uses.
My colleague pointed out that perhaps this needs to be a sink and that is treated differently? <- We may try that later and update but we are not sure right now.
My desire is from the top to replace the apis with mocks during testing. Does someone have an example for this?
Here is our bootstrap code that does not know if it is in production or inside a feature test. We test end to end results with no apache beam imports in our tests meaning we swap to any tech if we want to pivot and keep all our tests. Not only that, we catch way more integration bugs and can refactor without rewriting tests since the contracts we test are customer ones we can't easily change.
public class App {
private Pipeline pipeline;
private RosterFileTransform transform;
#Inject
public App(Pipeline pipeline, RosterFileTransform transform) {
this.pipeline = pipeline;
this.transform = transform;
}
public void start() {
pipeline.apply(transform);
pipeline.run();
}
}
Notice that everything we do is Guice Injection based so the Pipeline may be direct runner or not. I may need to modify this class to pass things through :( but anything that works for now would be great.
The function I am trying to get our api(and mock and impl to) with no serialization is thus
private class ValidRecordPublisher extends DoFn<Validated<PractitionerDataRecord>, String> {
#ProcessElement
public void processElement(#Element Validated<PractitionerDataRecord>element) {
microServiceApi.writeRecord(element.getValue);
}
}
I am not sure how to pass in microServiceApi in a way that avoid serialization. I would be ok with delayed creation as well after deserialization using guice Provider provider; with provider.get() if there is a solution there too.
Solved in such a way that mocks no longer need static or serialization anymore by one since glass bridging the world of dataflow(in prod and in test) like so
NOTE: There is additional magic-ness we have in our company that passes through headers from service to service and through dataflow and that is some of it in there which you can ignore(ie. the RouterRequest request = Current.request();). so for anyone else, they will have to pass in projectId into getInstance each time.
public abstract class DataflowClientFactory implements Serializable {
private static final Logger log = LoggerFactory.getLogger(DataflowClientFactory.class);
public static final String PROJECT_KEY = "projectKey";
private transient static Injector injector;
private transient static Module overrides;
private static int counter = 0;
public DataflowClientFactory() {
counter++;
log.info("creating again(usually due to deserialization). counter="+counter);
}
public static void injectOverrides(Module dfOverrides) {
overrides = dfOverrides;
}
private synchronized void initialize(String project) {
if(injector != null)
return;
/********************************************
* The hardest part is this piece since this is specific to each Dataflow
* so each project subclasses DataflowClientFactory
* This solution is the best ONLY in the fact of time crunch and it works
* decently for end to end testing without developers needing fancy
* wrappers around mocks anymore.
***/
Module module = loadProjectModule();
Module modules = Modules.combine(module, new OrderlyDataflowModule(project));
if(overrides != null) {
modules = Modules.override(modules).with(overrides);
}
injector = Guice.createInjector(modules);
}
protected abstract Module loadProjectModule();
public <T> T getInstance(Class<T> clazz) {
if(!Current.isContextSet()) {
throw new IllegalStateException("Someone on the stack is extending DoFn instead of OrderlyDoFn so you need to fix that first");
}
RouterRequest request = Current.request();
String project = (String)request.requestState.get(PROJECT_KEY);
initialize(project);
return injector.getInstance(clazz);
}
}
I suppose this may not be what you're looking for, but your use case makes me think of using factory objects. They may depend on the pipeline options that you pass (i.e. your PipelineOptions object), or on some other configuration object.
Perhaps something like this:
class MicroserviceApiClientFactory implements Serializable {
MicroserviceApiClientFactory(PipelineOptions options) {
this.options = options;
}
public static MicroserviceApiClient getClient() {
MyPipelineOptions specialOpts = options.as(MySpecialOptions.class);
if (specialOpts.getMockMicroserviceApi()) {
return new MockedMicroserviceApiClient(...); // Or whatever
} else {
return new MicroserviceApiClient(specialOpts.getMicroserviceEndpoint()); // Or whatever parameters it needs
}
}
}
And for your DoFns and any other execution-time objects that need it, you would pass the factory:
private class ValidRecordPublisher extends DoFn<Validated<PractitionerDataRecord>, String> {
ValidRecordPublisher(MicroserviceApiClientFactory msFactory) {
this.msFactory = msFactory;
}
#ProcessElement
public void processElement(#Element Validated<PractitionerDataRecord>element) {
if (microServiceapi == null) microServiceApi = msFactory.getClient();
microServiceApi.writeRecord(element.getValue);
}
}
This should allow you to encapsulate the mocking functionality into a single class that lazily creates your mock or your client at pipeline execution time.
Let me know if this matches what you want somewhat, or if we should try to iterate further.
I have no experience with Guice, so I don't know if Guice configurations can easily pass the boundary between pipeline construction and pipeline execution (serialization / submittin JARs / etc).
Should this be a sink? Maybe, if you have an external service, and you're writing to it, you can write a PTransform that takes care of it - but the question of how you inject various dependencies will remain.

How are domain events dispatched from within domain objects?

Domain objects shouldn't have any dependencies, hence no dependency injection either. However, when dispatching domain events from within domain objects, I'll likely want to use a centralised EventDispatcher. How could I get hold of one?
I do not want to return a list of events to the caller, as I'd like them to remain opaque and guarantee their dispatch. Those events should only be consumed by other domain objects and services that need to enforce an eventual consistent constraint.
See Udi Dahan's domain events
Basically, you register one or more handlers for your domain events, then raise an event like this:
public class Customer
{
public void DoSomething()
{
DomainEvents.Raise(new CustomerBecamePreferred() { Customer = this });
}
}
And all the registered handler will be executed:
public void DoSomethingShouldMakeCustomerPreferred()
{
var c = new Customer();
Customer preferred = null;
DomainEvents.Register<CustomerBecamePreferred>(p => preferred = p.Customer);
c.DoSomething();
Assert(preferred == c && c.IsPreferred);
}
This is basically implementing Hollywood Principle (Don't call us, we will call you), as you don't call the event handler directly - instead the event handler(s) get executed when the event is raised.
I'll likely want to use a centralised EventDispatcher. How could I get hold of one?
Pass it in as an argument.
It probably won't look like an EventDispatcher, but instead like some Domain Service that describes the required capability in domain specific terms. When composing the application, you choose which implementation of the service to use.
You are asking to have it both ways. You either need to inject the dependency or invert control and let another object manager the interaction between Aggregate and EventDispatcher. I recommend keeping your Aggregates as simple as possible so that they are free of dependencies and remain testable as well.
The following code sample is very simple and would not be what you put into production, but illustrates how to design Aggregates free of dependencies without passing around a list of events outside of a context that needs them.
If your Aggregate has a list of events within it:
class MyAggregate
{
private List<IEvent> events = new List<IEvent>();
// ... Constructor and event sourcing?
public IEnumerable<IEvent> Events => events;
public string Name { get; private set; }
public void ChangeName(string name)
{
if (Name != name)
{
events.Add(new NameChanged(name);
}
}
}
Then you might have a handler that looks like:
public class MyHandler
{
private Repository repository;
// ... Constructor and dependency injection
public void Handle(object id, ChangeName cmd)
{
var agg = repository.Load(id);
agg.ChangeName(cmd.Name);
repository.Save(agg);
}
}
And a repository that looks like:
class Repository
{
private EventDispatcher dispatcher;
// ... Constructor and dependency injection
public void Save(MyAggregate agg)
{
foreach (var e in agg.Events)
{
dispatcher.Dispatch(e);
}
}
}

Is this loginRequired(f)() the way to handle login required functions in dart?

I am new to Dart programming. I am trying to figure out what is the proper way (what everyone will do) to handle/guard those functions which are login required. The following is my first trial:
$ vim login_sample.dart:
var isLoggedIn;
class LoginRequiredException implements Exception {
String cause;
LoginRequiredException(this.cause);
}
Function loginRequired(Function f) {
if (!isLoggedIn) {
throw new LoginRequiredException("Login is reuiqred.");
}
return f;
}
void secretPrint() {
print("This is a secret");
}
void main(List<String> args) {
if (args.length != 1) return null;
isLoggedIn = (args[0] == '1') ? true : false;
try {
loginRequired(secretPrint)();
} on LoginRequiredException {
print("Login is required!");
}
}
then, run it with $ dart login_sample.dart 1 and $ dart login_sample.dart 2.
I am wondering if this is the recommended way to guard login required functions or not.
Thank you very much for your help.
Edited:
My question is more about general programming skills in Dart than how to use a plugin. In python, I just need to add #login_required decorator in the front of the function to protect it. I am wondering if this decorator function way is recommended in dart or not.
PS: All firebase/google/twitter/facebook etc... are blocked in my country.
I like the functional approach. I'd only avoid using globals, you can wrap it in a Context so you can mock then for tests and use Futures as Monads: https://dartpad.dartlang.org/ac24a5659b893e8614f3c29a8006a6cc
Passing the function is not buying much value. In a typical larger Dart project using a framework there will be some way to guard at a higher level than a function - such as an entire page or component/widget.
If you do want to guard at a per-function level you first need to decide with it should be the function or the call site that decides what needs to be guarded. In your example it is the call site making the decision. After that decision you can implement a throwIfNotAuthenticated and add a call at either the definition or call site.
void throwIfNotAuthenticated() {
if (!userIsAuthenticated) {
throw new LoginRequiredException();
}
}
// Function decides authentication is required:
void secretPrint() {
throwIfNotAuthenticated();
print('This is a secret');
}
// Call site decides authentication is required:
void main() {
// do stuff...
throwIfNotAuthenticated();
anotherSecreteMethod();
}

How to dynamically create a method or a setter in a class in Dart?

Is it possible to dynamically add an instance method or a setter to an existing class, either from within this class or from outside of it?
No, you can't add a real member to a class.
I said real member because you can simulate such feature with noSuchMethod(). Here a example :
#proxy
class A {
final dynamicMethods = <Symbol, Function>{};
noSuchMethod(Invocation i) {
if (i.isMethod && dynamicMethods.containsKey(i.memberName)) {
return Function.apply(dynamicMethods[i.memberName],
i.positionalArguments, i.namedArguments);
}
return super.noSuchMethod(i);
}
}
main() {
final a = new A();
a.dynamicMethods[#sayHello] = () => print('hello');
a.sayHello();
}
In the future this could perhaps be possible. See this excerpt from the article on Mirrors :
We’d like to support more powerful reflective features in the future. These would include mirror builders, designed to allow programs to extend and modify themselves, and a mirror-based debugging API as well.

Does the Dart programming language have an equivalent to Javascript's "prototype"?

In Dart, is it possible for a function to have a prototype associated with it?
Example Javascript code:
doStuff.prototype.isDefined = true; //is there anything like Javascript's function prototypes in Dart?
function doStuff(){
console.log("The function doStuff was called!");
}
Is it possible to do the equivalent of this in Dart (i.e., create a list of properties for each function?)
Two things to address here:
First, Dart doesn't have prototypes or prototypal inheritance, and instead uses classical inheritance. Rather than a prototype, objects have a class, and instead of a prototype chain, objects have superclasses.
Second, for your specific case, I think we'd have to see more of what you need to do to figure out the idiomatic way to do it in Dart. It should soon be possible to emulate functions with objects so that you can invoke an object and still have state and other methods associated with it.
See this article for more: http://www.dartlang.org/articles/emulating-functions/
When that capability lands you'll be able to do this:
class DoStuff {
bool isDefined = true;
call() => print("The function doStuff was called!");
}
var doStuff = new DoStuff();
main() => doStuff();
Which works if you have a fixed set of metadata about your function that you need to keep track of. It's slightly different from JavaScript because each instance of the function in Dart will have its own state for isDefined. I'm not sure if it's possible or easy to get multiple instances of the function in JavasScript, but you might need to make isDefined static so that the value is shared across all instances.
Dart does not allow you to add or remove member variables from an instance of a class at runtime. Rewriting your example in Dart it might look something like this:
class doStuff {
bool isDefined;
doStuff() {
isDefined = true;
}
void stuff() {
print('The function stuff was called!');
}
}
main() {
new doStuff().stuff();
}
If you wanted to add a property bag to a class in Dart you would write:
class PropertyObject {
Map<String, Dynamic> properties;
PropertyObject() {
properties = new Map<String, Dynamic>();
}
Dynamic operator[](String K) => properties[K];
void operator[]=(String K, Dynamic V) => properties[K] = V;
}
main() {
PropertyObject bag = new PropertyObject();
bag['foo'] = 'world';
print('Hello ${bag['foo']}');
}
Note that you can't access map properties using the '.' operator.

Resources