I have a set of ids called oppIdsInWrapper inner class. However while I build my wrapper, this is always null and empty. I want be able to reference this as I build my records to avoid duplicate ids. However it's as if this is re-created everytime I add to my wrapOppList.

If I place my Set at the upper class level and instantiate it in my controller, the inner class and wrapper do not recognize it:

"Variable does not exist: oppIdsInWrapper"

What am I doing wrong? Do I have really have to perform this logic before I build my wrapper here? :

wrapOppList.add(new wrapOpportunity(a, a.Apttus__Related_Opportunity__r.Opportunity__c));

Main Controller:

public class AgreementWithOppsController2 {

    public list<wrapOpportunity> wrapOppList { get; set; }

    public AgreementWithOppsController() {
        wrapOppList.add(new wrapOpportunity(a, a.Apttus__Related_Opportunity__r.Opportunity__c));


   public class wrapOpportunity{

    public Apttus__APTS_Agreement__c agreement{get;set;}
    public Boolean isSelected{get;set;}
    public Boolean isDisplayed{get;set;}
    public Set<Id> oppIdsInWrapper {get;set;}

       public wrapOpportunity(Apttus__APTS_Agreement__c a, String oppNumber){     

            oppIdsInWrapper = new Set<Id>();
            system.debug('expected to hit only one time?'); //this hits every time, why? where can i store this and access it?

         system.debug('id wrapper size: '+oppIdsInWrapper.size());

            isDisplayed = true;
            isDisplayed = false; //this never hits, why?
            system.debug('does this hit?');
            isSelected = false;

2 Answers 2


However it's as if this is re-created everytime I add to my wrapOppList.

That's exactly what's happening.

When you create a wrapper, you also create instance variables for all the variables you define in your class (isDisplayed, isSelected). These are all different objects, even if you have two instances of the same class. They will contain different data between two instances of the same class.

To share data in a transaction, you can create a static Set<Id>, and use that insead. Static is a keyword which essentially means "Theres one of this per class", while instance variables are "Theres one of this per object".

Take this example:

Dummy Class

public class DummyClass {
    public static Integer staticValue { get {
        f (staticValue == null) {
            staticValue = 0; 
        return staticValue; 
    } set; }

    public Integer instanceValue { get {
        if (instanceValue == null) {
            instanceValue = 0; 
        return instanceValue; 
    } set; }

    public DummyClass() {


List<DummyClass> wrappers = new List<DummyClass>(); 

for (Integer i = 0; i < 10; i++) {
    wrappers.add(new DummyClass());

System.assertEquals(wrappers.size(), DummyClass.staticValue);

for (DummyClass wrapper:wrappers) {
    System.assertEquals(1, wrapper.instanceValue);

For your code, use this line instead:

public static Set<Id> oppIdsInWrapper { get; set; }

Suddenly, all your code will start referencing the same data, because of the static clause. This variable is now defined for the class, and data in it will remain accessible until the end of the transaction.

That being said, it's probably easier to check for duplicates before creating your wrappers instead of delegating it to the wrappers themselves. Its kind of a code smell (a warning sign of poor programming practices or difficult to maintain code), but this could be an ideal solution in your case.

Additional Reading

  • 1
    Basically what I was going to say, but I would have also mentioned that static variables are not persisted in the view state, which may have other fun side effects.
    – sfdcfox
    Commented Feb 28, 2018 at 17:55

You're creating a new wrapOpportunity object with each call to wrapOppList.add(), so the oppIdsInWrapper will be null every time.

The logic to keep your collection of wrapOpportunity wrapper objects from having duplicate Ids doesn't belong in the wrapper class. It should be in your AgreementWithOppsController2 class, eg (you could also consider using a Set of your wrapper objects, but maintaining your use of a List of wrapper objects):

public class AgreementWithOppsController2 {

    public list<wrapOpportunity> wrapOppList { get; set; }
    public Set<Id> opIdsInWrappper = new Set<Id>(); 

    public AgreementWithOppsController() {
        if (! oppIdsInWrapper.contains(a.Apttus__Related_Opportunity__c)) {
            //no need to use __r.Id; the relationship field is the Id
            wrapOppList.add(new wrapOpportunity(a., a.Apttus__Related_Opportunity__r.Opportunity__c));

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .