2014年3月23日 星期日

牛奶湯底的玉米濃湯作法

   今天做了黑糊椒牛柳口味的Pizza, 覺得應該搭配玉米濃湯應該是不錯的搭配, 網上發現下面這個recipe做出來的口味真是不錯, 不過我做了些改良: 把蘑菇換成了杏苞菇, 也覺得應該吃到玉米粒, 所以多加了一罐玉米粒罐頭; 另外, 我覺得炒洋蔥也不見得需要, 所以也省下來這個炒的時間.
     說起來這濃湯不加粉勾芡確實傷本, 但是吃起來卻安心很多, 也吃得開心.

此處到原post網址
====
材料:
1.  全脂鮮奶1公升(用全脂的才香)
2.  洋蔥1顆(切細末)
3.  雞絞肉 100g
4. 杏苞菇(切小丁)
5. 紅蘿蔔 50g (切小丁)
6. 奶油 3大匙
7. 鹽巴 1茶匙
8. 玉米醬 1罐
9. 玉米粒 1罐

步驟
1. 將鮮奶以中小火加熱到滾, 奶油放在湯鍋中融化後, 將洋蔥, 杏苞菇, 紅蘿蔔, 雞胸肉放入
2. 玉米醬, 玉米粒倒入。
3.加熱期間不斷攪拌避免底不燒焦。
4.加熱至微微滾(不用到沸騰),再將鹽巴丟入,拌勻即可起鍋。


原post, 木不子的小心得:
1.濃湯中的食材切得越細小,濃湯會越順口,以前在瑞典時的法國室友還拿果汁機來做濃湯,剛開始不習慣久了發現,所有食材融合在一起的感覺滿棒的,一口湯可以喝到很多東西!
2.基本的湯底除了鮮奶.洋蔥之外,其他的食材都可以做不同的替換,例如放入馬鈴薯泥變成馬鈴薯濃湯,或是海鮮濃湯,變化很多大家可以多多嘗試!
3.鹽巴可加可不加,沒有加鹽巴的玉米濃湯味道會比較甜,不過那種甜不是像綠豆湯那種甜,而是洋蔥與玉米醬本身的甜味!
4.真正濃湯很適合搭配烤土司一起食用,撕片土司沾上濃湯,味道剛剛好。或許是考量到一般喝湯不搭配麵包的習慣,有許多餐廳的濃湯木不子都覺得不太濃,直接喝也剛剛好!如果有機會到美國的餐廳喝海鮮切達濃湯一定要搭配附贈的小餅乾,不然會濃到有點爆炸~~~~

2014年3月19日 星期三

Using Jackson to unmarshall Yahoo Weather RESTful web serice for Android Restful Client App


    While developing an Android application, it is mandatory that we may work with web services or SOA applications by exchanging XML or JSON data. Comparing to XML, JSON has been the preferred format, because it is much more lightweight. We will first consider about the JSON to Java object conversion. To unmarshall JSON document, the most popular pre-processors are Jackson and GSON. After some googling, I decided to use Jackson in my example to get JSON from Yahoo Weather, due to the better features and performance of Jackson. You may visit the discussion about Jackson Vs GSON on Stackoverflow.

    To use Jackson to unmarshall JSON document, you may follow steps as below:

Step1: Download jars of Jackson core module from Jackson and add reference for the jars in Eclipse
       Jackson core modules are the foundation on which extensions (modules) build upon. These are three and they are known as:
    Streaming ("jackson-core-2.2.3.jar") defines low-level streaming API, and includes JSON-specific implementations
    Annotations("jackson-annotations-2.2.3.jar") contains standard Jackson annotations
    Databind ("jackson-databind-2.2.3.jar") implements data-binding (and object serialization) support on streaming package; it depends both on streaming and annotations packages

        After adding the reference, you should be able to see them in Package Explorer.

Step2: Generate POJO from JSON schema or data
      POJO classes can be generated by tools. You may visit http://www.jsonschema2pojo.org and you can paste JSON schema or data into the left hand side textarea and name the package and class names. 

  Yahoo Weather Forecast
     To get weather forecast from Yahoo Weather YQL API, you can paste below URL in browser and you should be able to get a weather JSON data from Yahoo.  Well, yep, it's a SQL-like stuff. You can specify the preferred location, preferred unit(Celsius or Fahrenheit) and returned format to look up as below:
   http://query.yahooapis.com/v1/public/yql?q=select%20item%20from%20weather.forecast%20where%20location%3D%22TWXX0025%22%20and%20u=%22c%22&format=json
    

       You may wonder where you can get the location codes. No worry. To get the location code, please visit web site as below. You can find location codes for most of countries. The location codes are used for AOL weather, weather.com and Yahoo weather.



   JSON Formatter & Validator
         JSON formatter & validator can help you to validate whether the JSON data is well-form and provide you a better format to read.
         Please visit http://jsonformatter.curiousconcept.com for detail.

   jsonschema2pojo
        To generate POJO from JSON, you can do it manually, if the model is simply a java class. However, if it's complicated enough, I would think it's the better to generate them via tool and modify them accordingly. To my example, I actually didn't do any modification after code generation.
       The GUI of the web site is very simple. You can paste the JSON schema or data into the left hand side text area and press your preferred package name and class name. It's nice the tool can generate POJO for Jackson and GSON and even add more annotation styles for Joda and others.



    After pressing Preview button, it prompts a preview dialog to see the generated POJO classes. If you like the generated result, you can click Jar button to get the jar file with the POJO source code. 


    YahooWeather-source.jar can be download after pressing Jar button.   

  I decompress the jar file and move them to my project. If you like to download my POJO from jsonschema2pojo, you can download from here.


Step3: Use ObjectMapper to unmarshall JSON string from Yahoo Weather
      To use Jackson is simple. There're just few lines of code. 
ObjectMapper mapper = new ObjectMapper();
try {
 YahooWeather ym = mapper.readValue(jsonString, YahooWeather.class);
} catch (JsonGenerationException e) {
 Log.d("RestingTask", "Resting JsonGenerationException: " + e);
} catch (JsonMappingException e) {
 Log.d("RestingTask", "Resting JsonMappingException: " + e);
} catch (IOException e) {
 Log.d("RestingTask", "Resting IOException: " + e);
}


   Add an AsyncTask for my button action
package com.hitech.weather.task;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.os.AsyncTask;
import android.util.Log;
import android.widget.TextView;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hitech.weather.model.YahooWeather;
import com.hitech.weather.model.Forecast;

public class RestingAsyncTaskUnmarchall extends AsyncTask<String, String, String> {
 TextView tv = null;

 public RestingAsyncTaskUnmarchall(TextView tv) {
  this.tv = tv;
 }

 @Override
 protected String doInBackground(String... uri) {
  HttpClient httpclient = new DefaultHttpClient();
  HttpResponse response;
  String responseString = null;
  try {
   response = httpclient.execute(new HttpGet(uri[0]));
   StatusLine statusLine = response.getStatusLine();
   if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    response.getEntity().writeTo(out);
    out.close();
    responseString = out.toString();
    
    responseString = unmarchallJson(responseString);
   } else {
    // Closes the connection.
    response.getEntity().getContent().close();
    throw new IOException(statusLine.getReasonPhrase());
   }
  } catch (ClientProtocolException e) {
   Log.d("RestingTask", e.getMessage());
  } catch (IOException e) {
   Log.d("RestingTask", e.getMessage());
  }

  Log.d("RestingTask", responseString);
  return responseString;
 }

 @Override
 protected void onPostExecute(String result) {
  super.onPostExecute(result);
  // Do anything with response..
  tv.setText(result);
 }

 private String unmarchallJson(String jsonString) {
  ObjectMapper mapper = new ObjectMapper();
  StringBuffer sb = new StringBuffer();

  try {
   // read from file, convert it to user class
   YahooWeather ym = mapper.readValue(jsonString, YahooWeather.class);
   // display to console
   //System.out.println(example);
   sb.append("counts:");
   sb.append(ym.getQuery().getCount());
   sb.append("title:");
   sb.append(ym.getQuery().getResults().getChannel().getItem().getTitle());
   sb.append("whether:");
   List<Forecast> forecastList = ym.getQuery().getResults().getChannel().getItem().getForecast();
   for (int i=0; i<forecastList.size(); i++) {
    Forecast forecast = forecastList.get(i);
      sb.append("," + forecast.getDate() + ":(" + forecast.getLow() + "~" + forecast.getHigh() + "," + forecast.getText() + ")"); 
   }
   
  } catch (JsonGenerationException e) {
   Log.d("RestingTask", "Resting JsonGenerationException: " + e);
  } catch (JsonMappingException e) {
   Log.d("RestingTask", "Resting JsonMappingException: " + e);
  } catch (IOException e) {
   Log.d("RestingTask", "Resting IOException: " + e);
  }
  return sb.toString();
 }
}



Step4: Enjoy it!