Code Monkey home page Code Monkey logo

force-di's People

Contributors

afawcett avatar aronowt avatar bjanderson70 avatar claychipps avatar daveespo avatar douglascayers avatar fishofprey avatar imjohnmdaniel avatar lukethacoder avatar osieckiadam avatar peterlin888 avatar smukov avatar stohn777 avatar torynet avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

force-di's Issues

Provide Lightning component for App Builder

For simple use cases with Lightning pages where the developer just wants a Lightning component on the page that would only be using the <c:di_injector> tag, then to reduce the amount of boiler plate code developers need to bring to the table we can provide one for them.

This new component would expose design attributes via datasource so the admin can select from the list of CMDT bindings available.

This new component is a simple wrapper for <c:di_injector> tag for use with drag-n-drop in App Builder when creating Lightning pages.

For passing in custom attributes (<c:di_injectorAttribute>), need to continue to think about the design:

  • do we provide a handful of Attribute1, Attribute2, ..., AttributeN design attributes or
  • do we accept a single text field that accepts delimited key=value pairs, or
  • do we not and injector attributes are only supported via BYOC (bring your own component)

Use SOSL to generate bindings

Hi Andy

Great stuff.

One feature that might be of use instead of using custom metadata you could you SOSL to find your classes that extend di_module.

List<List<SObject>> results = [FIND ' extends di_Module' IN ALL FIELDS RETURNING ApexClass (Id, Name)];

for(SObject result : results.get(0)){
    System.debug(result.get('Name'));
}

It would be a relatively quick query and you could also cache the data in the platform cache.

I was contemplating using this to create my own annotations framework for DI but I thought it might be too temperamental and require too much processing time for the initial setup/config.

Although I'm not sure how this would work with unlocked packages if the code would be searchable or not.

Adjust directory structure

Small housekeeping issue.

The unit tests should be moved from force-di/main/default/classes/test over to /force-di/test/classes. Tests should be in their own directory away from the "main" code.

Apex Binding__mdt record to custom sobject fails

An exception is thrown when the di_Binding tries to load a Binding__mdt record that has the Binding Object (Binding__mdt.BindingObject__c) field mapped to a custom SObject (i.e. Widget__c).

Steps to reproduce

  • Setup Force-DI project
  • Create new Binding__mdt record.
    • QualifiedAPIName, DeveloperName, BindingSequence__c == some arbitrary value
    • Type__c == Apex
    • To__c == random string
    • BindingObject__c == Custom SObject like Widget__c
  • Execute anonymous: RuntimeBindingDemoOrg.run();

Exception seen

ERROR:  Execution failed.

 ▸    ERROR: System.InvalidParameterValueException: Invalid sobject provided.
 ▸    The Schema.describeSObject() methods does not support the 01i3b00000034c4
 ▸    sobject as a parameter. The sobject provided does not exist.
 ▸    ERROR: Class.di_Injector.CustomMetadataModule.configure: line 147, column
 ▸    1
 ▸    Class.di_Binding.Resolver.loadBindings: line 265, column 1
 ▸    Class.di_Binding.Resolver.get: line 277, column 1
 ▸    Class.di_Injector.getInstance: line 87, column 1
 ▸    Class.di_Injector.getInstance: line 60, column 1
 ▸    Class.RuntimeBindingDemoOrg.WelcomeApp.<init>: line 16, column 1
 ▸    Class.RuntimeBindingDemoOrg.run: line 30, column 1

Comments

The issue appears to be that when CMDT records with fields of the data type "Metadata Relationship(Entity Definition)", the value returned on that field in Apex will be the API name of the SObject if that SObject is a Standard SObject. If it contains the value of a Custom SObject, then the internal SObject Record ID is returned instead. That is not accepted on the Schema.describeSObject() method call in the di_Injector.CustomMetadataModule.configure() method call on line 147.

Error when binding value is modified in parent components init handler

Describe the bug
I am seeing an error when the binding value is modified in the parent component's init handler.

To Reproduce

  1. create a test lightning App

Testapp.app

<aura:application extends="force:slds">
	<aura:attribute name="buttonLabel" type="String" default="Neutral"/>
    
    <aura:handler name="init" value="{!this}" action="{!c.initHandler}"/>    

    <!-- create following button component using Force-DI -->
    <!-- <lightning:button label="Neutral"></lightning:button> -->   
    <c:di_injector bindingName="lc_button">
        <c:di_injectorAttribute name="label" value="{!v.buttonLabel}"/>
    </c:di_injector>
</aura:application>

TestappController.js

({
	initHandler : function(cmp, evt, helper) {
		cmp.set('v.buttonLabel', 'brand');
	}
})
  1. create custom metadata
    di_Binding.lc_button
<?xml version="1.0" encoding="UTF-8"?>
<CustomMetadata xmlns="http://soap.sforce.com/2006/04/metadata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <label>lc_button Binding</label>
    <protected>false</protected>
    <values>
        <field>BindingObjectAlternate__c</field>
        <value xsi:nil="true"/>
    </values>
    <values>
        <field>BindingObject__c</field>
        <value xsi:nil="true"/>
    </values>
    <values>
        <field>BindingSequence__c</field>
        <value xsi:nil="true"/>
    </values>
    <values>
        <field>To__c</field>
        <value xsi:type="xsd:string">lightning:button</value>
    </values>
    <values>
        <field>Type__c</field>
        <value xsi:type="xsd:string">LightningComponent</value>
    </values>
</CustomMetadata>

Steps to reproduce the behavior:

  1. Create a scratch org & deploy force-di package
  2. create lightning app & custom metadata as mentioned
  3. preview the app - /c/Testapp.app

Expected behavior
No error expected.

Screenshots and text of error observed
image

Version
Did you try to reproduce the problem against the latest force-di code? yes

Add support for Sub-Class

I was wondering if there is also support for sub-classes in force-di, like in the example below:

public static IContactsSelector newWithoutSharingInstance()
{
    return (IContactsSelector) di_Injector.Org.getInstance(ContactsSelector.WithoutSharing.class));
}

I am able to execute the code but I am not able to create a Custom Metadata record for this in di_Binding__mdt, as a "." is not allowed in the Binding Name.

Or is there another way of doing this?

The main use case is that I have a (sub)package within the application that requires a selector in an elevated context. To avoid code duplication we added a sub class in the main selector class..

public virtual inherited sharing class ContactsSelector extends fflib_SObjectSelector implements IContactsSelector 
{
   public ContactsSelector()
   { 
	super();
   } 

   public ContactsSelector(Boolean includeFieldSetFields, Boolean enforceCRUD, Boolean enforceFLS)
   {
	super(includeFieldSetFields, enforceCRUD, enforceFLS);
   }
   ...
   public without sharing class WithoutSharing extends ContactsSelector
   {
	public WithoutSharing()
	{
		super( true, false, false 	);
	}

	public override List<Contact> selectById(Set<Id> idSet)
	{
		return super.selectById(idSet);
	}
	...
   }
}

Null Pointer Exception found in certain scenarios

A Null Pointer exception has been observed in certain conditions. Specifically, the di_Injector's method getInstance(String, Schema.SObjectType, Object) could through an NPE when the bindingsFound returns a null entry.

        List<di_Binding> bindingsFound = this.Bindings.bySObject( bindingSObjectType )
                                            .byName( developerName.toLowerCase().trim() )
                                            .get();

        if ( bindingsFound == null || bindingsFound.isEmpty() ) {
            throw new InjectorException('Binding for "' + developerName + '" and SObjectType "' + bindingSObjectType + '" not found');
        }
        return bindingsFound[0].getInstance(params);

If bindingsFound contains a null in the first position of the list, the di_Bindings.getInstance(Object) call will fail.

Add support for binding param defaults

In force-di directory, add list of binding parameters to the Binding.cls class so that default parameters can be provided at config time.

Adding parameters at runtime via the current getInstance(params) method would merge the runtime parameters with the default parameters.

Binding parameters would have four properties:

  • Name (string)
  • Value (object)
  • Type (string of the type to help with conversion/mapping purposes, like String, Boolean, Decimal)
  • Overwritable (boolean, indicates if runtime parameters overwrite this param's value)

Both the Binding.cls for Apex API and the Binding__mdt needs to support the related binding parameters. For metadata configuration, propose a new Binding_Param__mdt whose parent is a Binding__mdt.

di_BingingParam Unit Test failure

When running the unit tests, I'm getting a failure for: di_BingingParamTest.givenStringsWhenGetParameterThenGetValues(), line 302...

System.assertEquals( testDateTime.dateGmt(), response.dateTimeValue ); // hours will be zero'ed out

I'm in NZ Summer Time time zone. The expected value: 2018-08-07, actual value: 2018-08-08
Running this at 8:00 am in NZ

di_PlatformCache silently fails

di_PlatformCache will silently fail under the following conditions:

  • di_Configurations__c.UsePlatformCacheToStoreBindings__c = true
  • di_Configurations__c.OrgCachePartitionName__c specifies a partition name that does not exist
  • the call to retrieve bindings specifies that "empty bindings are allowed"
di_Injector.Org.Bindings.byName(String)
                                        .bySObject(SObjectType)
                                        .emptyBindingsAllowed()
                                        .get();

Under these conditions, the call to di_Binding.get() method first tries to retrieve the bindings from the platform cache. If that returns no bindings and empty bindings are allowed, then the call to loadBindings() method is bypassed.

The root issue is in the method di_PlatformCache.isStoringBindingInPlatformCache(). That method currently only checks value in the di_Configurations__c.UsePlatformCacheToStoreBindings__c field and does not also consider that the partition specified in di_Configurations__c.OrgCachePartitionName__c may not be valid.

The fix should be to change the di_PlatformCache.isStoringBindingInPlatformCache() method to also consider if the partition specified is valid.

sObject Dependency Injection

Hello gentlemen. First of all, thanks for all your hard work. This is awesome.

I have a DI use case where I would like to inject an sObject based on the type of another sObject. So, for example, I have a lightning component that "hasRecordId" and it would like determine the sObject type of that record Id and pass that information along and get another related sObject in return, without having to have any knowledge of it, except that it can expect to get back an sObject that meets certain requirements. The idea here is to make the lightning component be versatile and capable of working with new sObjects based purely on the addition of an appropriate sObject and a CMDT entry that links them.

Essentially this is sObject dependency injection. So, I can for example, have the package work with Accounts and have a related object for it that has the fields etc my component is expecting to work with. Then, if I decide to install CPQ, now maybe I need a new similar sObject that does the same thing, but is linked to SBQQ__Quote__c instead of Account. In my case I am using these sObjects as many to many linking objects between an sObject in the package and other sObjects. I would like it to be dynamic and be able to add support for additional sObjects based simply upon adding a new linking object and a CMDT entry. This lets me still have working Salesforce reporting and I can work with any sObject without having to make any changes to my package and it's classes and components.

I know I can do this by just adding my own CMDT, but I am already using Force DI and it seems like a natural extension of Force DI. So, I was thinking I could simply add another field to the Force DI CMDT such as "Bound Object", and add some appropriate methods to Force DI. That way if I'm trying to bind an sObject, it's just a matter of filling out that field. You would simply leave it empty just as you do the "Binding Object" field, if you didn't need it. This way sObjects could be bound dynamically in all the same ways that Classes are. You don't have interfaces for sObjects, so the user is responsible for making sure the sObject will fit the requirements or it will cause errors, but that is unavoidable.

So, my question is, do you see any reason that this is not a good fit or that I should just make a different CMDT and not involve Force DI?

Thanks for your time,

Tory Netherton

Problem using force-di as a submodule in managed package

I am trying to deploy force-di as part of a managed package rather than package it as an external dependency. I have included force-di as a submodule and i am trying to deploy the code without modification into a scratch org with a namespace.

The deployment errors because the test suite metadata requires the names of the test classes to be prefixed by the namespace.

I would like the test suite to be modified or removed so that the repo can be deployed into an org with a namespace as is so that i don't have to fork the force-di repo or find some other means to make local changes.

I could copy the code and manually add the namespace prefix but this is a poor developer experience and means we are less likely to use the latest verison of the repo.

Without the namespace prefix i get the following error when deploying the repo into an org with a namespace:

Deploying v58.0 metadata to [email protected] using the v59.0 SOAP API.
Deploy ID: 0Af3G0000116L3qSAE
Status: Failed | ████████████████████████████████████████ | 1/1 Components (Errors:1) | 0/0 Tests (Errors:0)

Component Failures [2]

| Type Name Problem
| ───── ─────────────────── ─────────────────────────────────────────
| Error force_di_teststuite No classes found for di_BindingParamTest.
| Error force_di_teststuite No classes found for di_BindingParamTest.

di_PlatformCacheTest test fail without Manage Internal Users permission.

Is your feature request related to a problem? Please describe.
The givenANewConfigSettingThenGetThatInstance and givenReadOnlyAccessThenGetInstance in the di_PlatformCacheTest require the system permission, Manage Internal Users to insert users with the Read Only or Minimum Access - Salesforce profiles. Without this permission, you will receive the following error:

System.DmlException: Insert failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Required fields are missing: [ProfileId]: [ProfileId]

Describe the solution you'd like
Commented out test methods

Describe alternatives you've considered

Additional context
Add any other context or screenshots about the feature request here.

Binding Resolver should provide option to not reload PlatformCache if bindings are not found

The current logic around di_Binding.Resolver.get() method first tries to find the bindings from Platform Cache assuming that it is enabled. If those bindings are not found and Platform Cache is enabled, then the assumption is that a new binding must have been introduced into the org since that last cache reload and we should then execute the di_Binding.Resolver.loadBindings() method.

Having said that, there are use cases where bindings are not required. Selector Field Injection is one of those use cases. In that use case, there needs to be a way to designate that a reload to memory of the bindings is not required.

This enhancement request covers that use case.

BindingObjectAlternate__c is not working

BindingObjectAlternate__c is not working when I put a value on it. I am using this on the Task object for binding object but cannot find it in the list. So I decided to use BindingObjectAlternate__c but no luck.
When I check the code, It's not included in the select statement and in the if statement. Please see below screenshot:
image

Please let me know if you know how to fix this.

Thanks and regards,
Divino Brinas

Apply di_ prefix to components

Eventually, we will create a 2GP namespaced package version of this lib (with the di_ prefix removed from its public facing API) as an additional means to consume this lib for those that prefer that. Meanwhile, we will assume early adopters will want to use the library as-is and thus to scope its components using the prefix approach. This also works well for ISV's and Enterprise devs, who may not want to depend on the 2GP namespaced unlocked package, but still, want the segregation a prefix gives in their broader code base.

di_Binding__mdt.BIndingObject__c data type does not support all SObject types

@afawcett and @douglascayers -- FYI, last week we came across a use case that showed that the MetadataRelationship to EntityDefinition data type for the di_Binding__mdt.BindingObject__c field does not support all SObject types available. Most notably is that it does not support the User SObject, but it also does not support several other SObjects including BusinessHours, Event, FiscalYearSettings, Group, Holiday, and several others.

This is most definitely a limitation with the MetadataRelationship EntityDefinition data type and not the Force-DI code. The question becomes how to accommodate these other SObjects from the di_Binding__mdt record.

I can think of two solutions.
A) add a new field on di__Binding__mdt called BindingObjectAlternate__c which would be a TEXT(255) data type. We could allow the admin to use this field to specify an SObject API name not covered by BindingObject__c. We would adjust the code that loads the bindings to use the BindingObject__c field first or the BindingObjectAlternate__c second for the API Binding name. We could also put a validation rule in place to throw an error if both fields were populated.

B) we change the data type of BindingObject__c to be simply TEXT(255) and thus remove the limitation all together.

What are your thoughts on this subject?

Write more Apex tests

Continue to expand out the tests in the /tests sub-folder and those in the sample apps.

Cache Resolved Bindings

Support caching support to improve performance of resolving bindings, particularly when there are dozens to hundreds and the bindings do complex processing.

Subscriber would provide a platform cache name for a partition they make available for this purpose. This will need a new setting somewhere to capture this.

Two main points where to utilize caching:

  • Binding.Resolver.get() method
  • Injector.CustomMetadataModule

Cache keys should be the unique name for the binding, and this requires code changes to ensure bindings have a unique name regardless where they are created from (custom metadata or programmatically).

di_PlatformCache treats "lists of bindings" and a "single binding"

If there are multiple bindings with the same developerName and SObjectType, the regular di_Binding.loadBindings() works with them as a group. But, when the method calls the di_PlatformCache.addBindingToPlatformCache() method, it places that one binding into the platform cache using the specific key value. If there are more bindings that match the same developerName and SObjectType, the previous binding is replaced with the new one in the platform cache. Essentially, the last binding added to the cache is the one that remains. This leads to erroneous behavior and errors.

Optimize di_Injector.CustomMetadataModule class

The di_Injector.CustomMetadataModule class makes Schema.describeSObjects() call within a method. The concern is that this is an expensive call and could be optimized if it were outside of the main For Loop.

Tasks:

  • Analysis of impacts
  • Make changes if it would be beneficial

Need info regarding some Force-DI behaviors

I am trying to use Force-di hence I have a question related to auto-launched or record-triggered flow. How can we manage them using Force-Di? Is there a way or we should not try DI for such flows? Thank you!
And also how we can manage the force-di in an efficient way with frameworks like trigger, logging etc.
Thank you so much,

Multiple bindings for a developer name

Hey, first of all, I would like to say thanks for this library, it really saved me a tons of time, great work!
I'm working on switching my org to unlocked packages, so I want to remove compile-time dependencies wherever possible and obviously dependency injection is a great technique to achieve that.
However I came across an issue, and I'm wondering now if my understanding of the problem is correct. I want to separate the implementation of some of my features (let's take a logger as an example) from the interface, as described here https://medium.com/salesforce-architects/5-anti-patterns-in-package-dependency-design-and-how-to-avoid-them-87bb50331cb8 (point 3). What is recommended there is to create package-a containing mock and interface to keep actual implementation separated from the interface.
image
Let's say that the logger feature (package-b) is depending on multiple different packages, and when a developer wants to use logger in his package, I don't want it to be necessary to install the package with the concrete implementation.
I would like also to be possible in the future to have multiple different orgs with different concrete implementations of the logger. This is why I came to a conclusion that I would like to have some basic implementation in 'package-a' which is mocking the logger both in tests and in normal code execution. Package-a contains a base, mock implementation and custom metadata record, but when the package with concrete implementation is installed on org (package-b), I would like force-di to use that one instead. This is the part where I would see multiple bindings for a single entity (let's say class) to be possible. Right now this is possible for SObject bindings (thanks to field Sequence we can order multiple bindings for some objects). I want to have this option for all bindings not only those related to SObjects.
I know that this could be easily achieved by implementing my own di_Module, but what do you think about making it more 'native'? I created this on my feature branch https://github.com/osieckiAdam/force-di/tree/feature/enable-multiple-bindings-for-developer-name but the reason why I'm not creating a pull request is that I'm not sure if this is a good idea in general to use this multi-binding approach

Unit of work slower when cache is enabled.

Describe the bug
Hello! We are trying to optimize our code and is looking at enabling di_Configurations__c.UsePlatformCacheToStoreBindings__c
And we are noticing that the UnitOfWork newInstance is slower when cache is enabled. I might be wrong but it seems that if cache is enabled, it is adding the binding to the cache but not using the cached binding in the succeeding execution?

To Reproduce
I have in total:

  • 8 domain bindings
  • 26 selector bindings
  • 19 service bindings
  • 6 unit of working bindings

In a scratch org, running the code below yields these CPU time results:
 fflib_ISObjectUnitOfWork uow = new fflib_SObjectUnitOfWork();

  • Disabled cache CPU time: 222 out of 10000
  • Enabled cache CPU time (3rd execution): 585 out of 10000

Selector test with 1 id, WHERE ID IN condition
List<XObject> tickets = XObjectSelector.newInstance().selectByIds(new Set<String> { 'XObjectID' });

  • Disabled cache CPU time: 254 out of 10000
  • Enabled cache Maximum CPU time: 0 out of 10000 --

Expected behavior
Faster execution is our expected result which we found in both Selector and Domain. Unfortunately the UnitOfWork newInstance is slower when cache is enabled.

Screenshots and text of error observed
Unit of work, cache Disabled
image

Unit of work, cache Enabled (3rd Execution)
image

Version
yes, we have the latest

Add git tags for versions

It would be great to be able to reference a version by git tag, for development and dependency management. Is there a reason not to do so?
Versions with no corresponding tags are already cited in sfdx-project.json.

Calling LWC

Hi, @ImJohnMDaniel - Good day! I would like to ask if it's possible to use LWC for DI. We are blocked because we cannot call LWC from LComponent because LWC doesn't have auraID to call with. IF it's possible to use LWC for DI, How can we achieve it via code? OR things that we need to consider updating your code to apply to call of LWC?

Cheers!

Thanks and regards,
Dino Brinas

di_Binding.Resolver ignores optional bindings when platform cache is off

In the di_Binding.Resolver.get() method, if the di_PlatformCache.getInstance().retrieveBindings(String, Schema.SObjectType) method does not return matchedBindings and di_Binding.Resolver.bindingsAreRequired is false (which means "empty bindings are allowed"), then the logic from the loadBindings() method is never called.

Support optional Apex Bindings

Following my last blog and the code samples in its summary.... I am wondering if an option for the Apex Injector to optionally require a binding if the binding reference (the class) is in-fact also the implementation. This would support simple cases where the developer just wants to use the Injector to add injection for a one off type thats not subclassed., but is a dependency they want to mock.

Automatically prefix Lightning component bindings with `c:` if no namespace provided

Human errors and typos are inevitable. I often forget to prefix my Lightning component names with c: prefix.

This request is for the binding resolver to automatically prefix with c: if no namespace is provided in the CMDT or programmatic binding.

No namespace means that the binding name does not include a colon :.

For a given Lightning component whose developer name is c:MyComponent then both these binding name variants should work:

  • c:MyComponent
  • MyComponent

For Lightning components that belong to a specific namespace (not c), then the full namespace and colon are required.

Force-DI does not resolve API-only namespaced metadata bindings

If you have a binding record that does not bind to an SObject and only binds to the API "developerName", that binding record will be ignored when executing in a namespaced scratch org.

The di_Binding.Resolver.isBindingMatchByFilteringCriteria( di_Binding ) method fails to make a match because the value for this.developerName is generated from the System.Type which includes the namespace value but the bind.DeveloperName doesn't included the namespace because its value was manually entered into the associated CMDT Binding__mdt record.

If you were to enter the namespace along with the API name into the CMDT Binding__mdt record, the resolution would work fine but that in turn limits your interaction with that codebase to only namespace enabled scratch orgs.

di_BindingTest.Bob does not implement the Provider Interface

Hi there folks.

We have not updated our common library in a while so this just may be an interconnected issue, but I am getting a weird error when creating a new version of the ForceDI library.

I have updated our local repositories (in bitbucket) with the latest code from the common github library. ApexMocks compiled and updated without issue. When I move to ForceDI to update and create a new version, I run it with the --codecoverage parameter and get this error:

Apex Test Failure: Class.di_Binding.ApexBinding.newInstance: line 413, column 1
Class.di_Binding.getInstance: line 82, column 1
Class.di_Binding.getInstance: line 70, column 1
Class.di_BindingTest.givenApexBindingWhenGetNewInstanceThenNewInstance: line 53, column 1 di_Binding.BindingException: Apex binding di_BindingTest.Bob implementation di_BindingTest.Bob does not implement the Provider interface.

Any ideas on what this might be? Is the Provider interface in another library or did I screw up on my steps updating this library?

Thank you.
Eric

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.