2

I was debugging my method and it somehow updates my element variable. Even if I don't work with that variable from within the method.

CODE:

private static List<Mapping> createFormFieldsMapping(ArrayList<String> CDOfields,
            List<Mapping> fieldMappings, Element element) {
        System.out.println(" - Creating field mappings for "+element.name);
        for (Mapping fieldMapping : fieldMappings){
            if (fieldMapping.targetEntityFieldId!=null){
                String formField = getContactFieldNameById(fieldMapping.targetEntityFieldId);
                formField = formField.trim();
                formField = formField.replaceAll("-", "");
                formField = formField.replaceAll("_", "");
                formField = formField.replaceAll(" ", "");
                formField = formField.toLowerCase();
                Boolean matchFound = false;
                for (String cdoField : CDOfields){
                    String[] cdoFieldSplit = cdoField.split(";",-1);
                    String cdoFieldModified =cdoFieldSplit[1].trim();
                    cdoFieldModified = cdoFieldModified.replaceAll("-", "");
                    cdoFieldModified = cdoFieldModified.replaceAll("_", "");
                    cdoFieldModified = cdoFieldModified.replaceAll(" ", "");
                    cdoFieldModified = cdoFieldModified.toLowerCase();
                    if (cdoFieldModified.equals(formField)){
                        fieldMapping.targetEntityFieldId = cdoFieldSplit[0];
                        matchFound = true;
                        break;
                    }
                    if (!matchFound){
                        // WRITE NOT MATCHED FORM FIELD TO A FILE
                    }
                }
            }
        }

element.processingSteps.targetEntityFieldId is being changed

This is the way I call the method:

List<Mapping> fieldMapping = new ArrayList<Mapping>();
Iterator<ProcessingStep> i = element.processingSteps.iterator();

while (i.hasNext()) {
       ProcessingStep step = i.next(); 
       if (step.type.equals("FormStepCreateUpdateContactFromFormField")){
           fieldMapping = step.mappings;
           step.execute = "never";
           //i.remove();
        }
     }
// Update contact field IDs with CDO field IDs
    fieldMapping = createFormFieldsMapping(CDOfields, fieldMapping, element);

Everything I wanted was to kind of copy field mapping, process it by that method and then return back and add it to list of fieldMappings.

The thing is that step.mappings is part of element, but that step.mappings is being put to an ArrayList fieldMapping. By that I would assume that element should never be edited by anything.

Ondrej Tokar
  • 4,898
  • 8
  • 53
  • 103
  • You are reassigning, not directly changing. – Malik Brahimi May 21 '15 at 14:13
  • "I was debugging my method and it somehow updates my element variable" - no it doesn't. The value of the `element` variable is exactly the same as it was before - it's a *reference* to an object. The data within that object has may have changed (it's not clear where it would within the code you've posted), but that's not the same thing. – Jon Skeet May 21 '15 at 14:14
  • 1
    Also some good answers here http://stackoverflow.com/q/7893492/2991525 – fabian May 21 '15 at 14:14
  • Why has my question been marked as duplicate? It isn't a duplicate. I haven't asked if Java is pass-by-reference or pass-by-value. I have stated in the title of the question that I know that it is pass-by-value... That is a totally different question. – Ondrej Tokar May 21 '15 at 14:14
  • @OndrejTokar time to start diving into the smelly belly of the beast, then. Check that your other methods don't sneak in modifications of your element object in any way by the back door as some kind of "convenience" or normalising step. – user268396 May 21 '15 at 14:20
  • Are you sure the `element.processingSteps` doesn't occur in `fieldMappings`. It may have been wrong to close your question as duplicate, but it certainly wasn't wrong to close the question, since there isn't enough information to identify the problem. If you add the relevant information and provide a good edit summary, it should go through the reopen review queue. – fabian May 21 '15 at 14:41
  • @fabian thanks for pointing out issues with my question. I would like to provide more information but I don't know what would help since I have no idea what causes the problem. The answer to your question, `element.processingSteps` contains `fieldMappings`. – Ondrej Tokar May 21 '15 at 14:45
  • 1
    I'm voting for reopen since this isn't really a duplicate: the OP isn't about java being call-by-value; It's about a specific problem! – fabian May 21 '15 at 15:02
  • 1
    Is it the case that `fieldMappings == element.processingSteps`? That is to say, that those two declarations point to the *same* reference? – Makoto May 21 '15 at 15:25
  • Might be, but how then I create a new arraylist of mapping o jects instead of pointing to the same one as element.processingSteps? – Ondrej Tokar May 21 '15 at 15:27
  • @Makoto as you said, if this is the case, then: `fieldMapping.targetEntityFieldId = cdoFieldSplit[0];` is reassigning the value here. Although java is pass-by-value, as you've seen in other comments/posts, the references are also passed by value, which gives a pseudo-pass-by-reference result when it comes to calling methods on passed references. Thus causing your changes. – Ricky Mutschlechner May 21 '15 at 15:27

1 Answers1

1

I believe this is because changing fieldMapping in this code also changes element because both are "references" to the same object:

fieldMapping.targetEntityFieldId = cdoFieldSplit[0];

To verify this is the case, add a conditional debug break (or an if-statement and a print/log) that checks the equality of the two object instances.

This is happening because you are setting fieldMapping equal to the object pointed to by your element.processingSteps.iterator() in following code.

Iterator<ProcessingStep> i = element.processingSteps.iterator();

while (i.hasNext()) {
       ProcessingStep step = i.next(); 
       if (step.type.equals("FormStepCreateUpdateContactFromFormField")){
           fieldMapping = step.mappings;
           step.execute = "never";
           //i.remove();
        }
     }
// Update contact field IDs with CDO field IDs
    fieldMapping = createFormFieldsMapping(CDOfields, fieldMapping, element);

If you do not want this behavior, then you need to "deep copy" the step.mappings object when initializing fieldMapping.

Makoto
  • 104,088
  • 27
  • 192
  • 230
jatal
  • 790
  • 1
  • 10
  • 19
  • I think you are right, I will try it as soon as I get home. However, how do you call that behavior? That even if I have created new ArrayList fieldMapping and put step.mappings in there, it is still just a reference to the same object? – Ondrej Tokar May 21 '15 at 15:55
  • 2
    ArrayList is a container for pointers, and pointers are objects that store a reference. This enables the By-Value nature of java, where the pointers are copied By-Value, but the object referenced by the pointer (i.e. the pointer's value) is still the same. This enables much of Java's speed since inception, since it could avoid copying entire objects (which get pretty big in Java). – jatal May 21 '15 at 16:10