package falgout.jrepl;

import com.google.common.reflect.TypeToken;

public class Variable<T> {
    private final TypeToken<T> type;
    private T value;
    
    public Variable(T value, TypeToken<T> type) {
        this.type = type;
        this.value = value;
    }
    
    public Variable(T value, Class<T> clazz) {
        this(value, TypeToken.of(clazz));
    }
    
    public TypeToken<T> getType() {
        return type;
    }
    
    public T get() {
        return value;
    }
    
    public void set(T value) {
        this.value = value;
    }
    
    @SuppressWarnings("unchecked")
    public <E> boolean set(E value, TypeToken<E> type) {
        if (this.type.isAssignableFrom(type)) {
            this.value = (T) value;
            return true;
        }
        
        return false;
    }
    
    public <E> boolean set(Variable<E> other) {
        return set(other.get(), other.getType());
    }
    
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((value == null) ? 0 : value.hashCode());
        return result;
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        Variable<?> other = (Variable<?>) obj;
        if (value == null) {
            if (other.value != null) {
                return false;
            }
        } else if (!value.equals(other.value)) {
            return false;
        }
        return true;
    }
    
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Variable [type=");
        builder.append(type);
        builder.append(", value=");
        builder.append(value);
        builder.append("]");
        return builder.toString();
    }
}

@@ -89,16 +89,37 @@
 le%3CT%3E %7B%0A
+    private T value;%0A
     priv
@@ -155,31 +155,45 @@
     private 
-T value
+final boolean isFinal
 ;%0A    %0A    p
@@ -220,54 +220,128 @@
 ue, 
-TypeToken%3CT%3E type) %7B
+Class%3CT%3E clazz) %7B%0A        this(value, TypeToken.of(clazz));%0A    %7D
 %0A    
+%0A
     
-this.type =
+public Variable(T value, TypeToken%3CT%3E
  type
-;
+) %7B
 %0A   
@@ -345,38 +345,44 @@
         this
-.
+(
 value
- = value
+, type, false)
 ;%0A    %7D%0A    
@@ -407,38 +407,58 @@
 le(T value, 
-Class%3CT%3E clazz
+TypeToken%3CT%3E type, boolean isFinal
 ) %7B%0A        
@@ -465,36 +465,80 @@
 this
-(
+.
 value
-, TypeToken.of(clazz))
+ = value;%0A        this.type = type;%0A        this.isFinal = isFinal
 ;%0A  
@@ -683,12 +683,15 @@
 lic 
-void
+boolean
  set
@@ -710,35 +710,140 @@
         
-this.value = value;
+if (isFinal) %7B%0A            return false;%0A        %7D else %7B%0A            this.value = value;%0A            return true;%0A        %7D
 %0A    %7D%0A 
@@ -1002,55 +1002,29 @@
     
-this.value = (T) value;%0A            return true
+return set((T) value)
 ;%0A  

Variables can be final