简体   繁体   中英

Java Object Reference Problems?

I have the following classes;

public class Payload{

    private Map<String, Object> map;

    public static Payload INSTANCE = new Payload();

    private Payload(){
        map = new HashMap<>();
    }

    public Payload put(String key, Object value){
        map.put(key, value);
        return this;
    }

    public Map<String, Object> getMap(){
        return map;
    }
}

public class AjaxRequestBinder {

    private String url;
    private String method;
    private Map<String, Object> data;
    private String dataType;

    public AjaxRequestBinder(String url, String method, Payload payload, AjaxDataType dataType) {
        this.url = url;
        this.method = method;
        this.data = payload != null ? payload.getMap() : Payload.INSTANCE.getMap();
        this.dataType = dataType != null ? dataType.name() : AjaxDataType.html.name();
    }
    //... getters() & setters()
}

public List<AjaxRequestBinder> getSampleAjaxBinders() throws Exception {
    List<AjaxRequestBinder> requestBinders = new ArrayList<>();
    requestBinders.add(new AjaxRequestBinder(getEndpointURL(ServiceModule.CAT), HttpMethod.GET.name(), null, AjaxDataType.json));
    requestBinders.add(new AjaxRequestBinder(getEndpointURL(ServiceModule.DOG), HttpMethod.GET.name(), null, AjaxDataType.json));
    requestBinders.add(new AjaxRequestBinder(getEndpointURL(ServiceModule.CHICKEN), HttpMethod.GET.name(), null, AjaxDataType.json));
    requestBinders.add(new AjaxRequestBinder(getEndpointURL(ServiceModule.GOAT), HttpMethod.GET.name(), null, AjaxDataType.json));
    requestBinders.add(new AjaxRequestBinder(getEndpointURL(ServiceModule.RABBIT), HttpMethod.POST.name(), buildPayload(ServiceModule.RABBIT, HttpMethod.POST), AjaxDataType.json));
    return requestBinders;
}

public Payload buildPayload(ServiceModule module, HttpMethod httpMethod) throws Exception {
    Payload payload = Payload.INSTANCE;
    module = module != null ? module : ServiceModule.NONE;

    if(httpMethod.equals(HttpMethod.POST)){

        switch(module){
            case CAT:{
                // Do nothing
            }break;
            case DOG:{
                // Do nothing
            }break;
            case CHICKEN:{
                // Do nothing
            }break;
            case GOAT:{
                // Do nothing
            }break;
            case RABBIT:{
                payload.put("color", "white").put("action", "hops");
            }break;
        }
    }else{
        throw new NotYetImplementedException();
    }
    return payload;
}

But for some odd reason, when method getSampleAjaxBinders() is called, it returns a list of AjaxRequestBinder objects with each and every one of them having;

data = {"color":"white", "action":"hops"}

whereas this is required for only the last added item. All the previously added items should simply have data = {} (empty map). When I step-debug through the method, I find out that all is well until buildPayload(ServiceModule module, HttpMethod httpMethod) is called which then automatically overwrites the empty maps in the previously added items of the list.

Can somebody please explain to me what might be responsible for this odd object reference problems being exhibited here;

This happens because you always use a single instance of Payload , which happens to be set for RABBIT .

Your buildPayload method returns payload which is set to the shared instance:

Payload payload = Payload.INSTANCE;

At the same time, when you pass null payload to AjaxRequestBinder constructor, the constructor uses the same Payload.INSTANCE :

this.data = payload != null ? payload.getMap() : Payload.INSTANCE.getMap();

You can fix it either by making Payload constructor public and creating new instances in buildPayload , or making a separate empty instance of Payload for using in cases when null is supplied to AjaxRequestBinder constructor:

public static final Payload INSTANCE = new Payload();
// Add this line to Payload
public static final Payload EMPTY = new Payload();
...
// Use EMPTY payload when the caller does not supply an actual one:
this.data = payload != null ? payload.getMap() : Payload.EMPTY.getMap();

Note that if you continue with the shared instance approach above, you would need to clear the map in the buildPayload method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM