class CacheGetResult<V> extends CacheResult {
    private volatile V value;
    private volatile CacheValueHolder<V> holder;

    public static final CacheGetResult NOT_EXISTS_WITHOUT_MSG = new CacheGetResult(CacheResultCode.NOT_EXISTS, null, null);
    public static final CacheGetResult EXPIRED_WITHOUT_MSG = new CacheGetResult(CacheResultCode.EXPIRED, null ,null);

    public CacheGetResult(CacheResultCode resultCode, String message, CacheValueHolder<V> holder) {
        super(CompletableFuture.completedFuture(new ResultData(resultCode, message, holder)));
    }

    public CacheGetResult(CompletionStage<ResultData> future) {
        super(future);
    }

    public CacheGetResult(Throwable ex) {
        super(ex);
    }

    public V getValue() {
        waitForResult();
        return value;
    }

    @Override
    protected void fetchResultSuccess(ResultData resultData) {
        holder = (CacheValueHolder<V>) resultData.getOriginData();
        value = (V) unwrapValue(holder);
        super.fetchResultSuccess(resultData);
    }

    static Object unwrapValue(Object holder) {<FILL_FUNCTION_BODY>}


    @Override
    protected void fetchResultFail(Throwable e) {
        value = null;
        super.fetchResultFail(e);
    }

    protected CacheValueHolder<V> getHolder() {
        waitForResult();
        return holder;
    }
}

        // if @Cached or @CacheCache change type from REMOTE to BOTH (or from BOTH to REMOTE),
        // during the dev/publish process, the value type which different application server put into cache server will be different
        // (CacheValueHolder<V> and CacheValueHolder<CacheValueHolder<V>>, respectively).
        // So we need correct the problem at here and in MultiLevelCache.unwrapHolder
        Object v = holder;
        while (v != null && v instanceof CacheValueHolder) {
            v = ((CacheValueHolder) v).getValue();
        }
        return v;
    
<methods>public void <init>(CompletionStage<com.alicp.jetcache.ResultData>) ,public void <init>(com.alicp.jetcache.CacheResultCode, java.lang.String) ,public void <init>(java.lang.Throwable) ,public CompletionStage<com.alicp.jetcache.ResultData> future() ,public java.lang.String getMessage() ,public com.alicp.jetcache.CacheResultCode getResultCode() ,public boolean isSuccess() ,public static void setDefaultTimeout(java.time.Duration) ,public void setTimeout(java.time.Duration) ,public void waitForResult(java.time.Duration) <variables>private static java.time.Duration DEFAULT_TIMEOUT,public static final com.alicp.jetcache.CacheResult EXISTS_WITHOUT_MSG,public static final com.alicp.jetcache.CacheResult FAIL_ILLEGAL_ARGUMENT,public static final com.alicp.jetcache.CacheResult FAIL_WITHOUT_MSG,public static final java.lang.String MSG_ILLEGAL_ARGUMENT,public static final com.alicp.jetcache.CacheResult PART_SUCCESS_WITHOUT_MSG,public static final com.alicp.jetcache.CacheResult SUCCESS_WITHOUT_MSG,private final non-sealed CompletionStage<com.alicp.jetcache.ResultData> future,private volatile java.lang.String message,private volatile com.alicp.jetcache.CacheResultCode resultCode,private volatile java.time.Duration timeout