The name reflection is used to describe code which is able to inspect other code in the same system (or itself).
For example, say you have an object of an unknown type in Java, and you would like to call a 'doSomething' method on it if one exists. Java's static typing system isn't really designed to support this unless the object conforms to a known interface, but using reflection, your code can look at the object and find out if it has a method called 'doSomething' and then call it if you want to.
So, to give you a code example of this in Java (imagine the object in question is foo) :
Method method = foo.getClass().getMethod("doSomething", null);
method.invoke(foo, null);
One very common use case in Java is the usage with annotations. JUnit 4, for example, will use reflection to look through your classes for methods tagged with the @Test annotation, and will then call them when running the unit test.
There are some good reflection examples to get you started at http://docs.oracle.com/javase/tutorial/reflect/index.html
And finally, yes, the concepts are pretty much similar in other statically typed languages which support reflection (like C#). In dynamically typed languages, the use case described above is less necessary (since the compiler will allow any method to be called on any object, failing at runtime if it does not exist), but the second case of looking for methods which are marked or work in a certain way is still common.
Update from a comment:
The ability to inspect the code in the system and see object types is
not reflection, but rather Type Introspection. Reflection is then the
ability to make modifications at runtime by making use of
introspection. The distinction is necessary here as some languages
support introspection, but do not support reflection. One such example
is C++
I've defined the following property as we use this often in unit testing.
public static string AssemblyDirectory
{
get
{
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);
}
}
The Assembly.Location
property sometimes gives you some funny results when using NUnit (where assemblies run from a temporary folder), so I prefer to use CodeBase
which gives you the path in URI format, then UriBuild.UnescapeDataString
removes the File://
at the beginning, and GetDirectoryName
changes it to the normal windows format.
Best Solution
A tag for a field allows you to attach meta-information to the field which can be acquired using reflection. Usually it is used to provide transformation info on how a struct field is encoded to or decoded from another format (or stored/retrieved from a database), but you can use it to store whatever meta-info you want to, either intended for another package or for your own use.
As mentioned in the documentation of
reflect.StructTag
, by convention the value of a tag string is a space-separated list ofkey:"value"
pairs, for example:The
key
usually denotes the package that the subsequent"value"
is for, for examplejson
keys are processed/used by theencoding/json
package.If multiple information is to be passed in the
"value"
, usually it is specified by separating it with a comma (','
), e.g.Usually a dash value (
'-'
) for the"value"
means to exclude the field from the process (e.g. in case ofjson
it means not to marshal or unmarshal that field).Example of accessing your custom tags using reflection
We can use reflection (
reflect
package) to access the tag values of struct fields. Basically we need to acquire theType
of our struct, and then we can query fields e.g. withType.Field(i int)
orType.FieldByName(name string)
. These methods return a value ofStructField
which describes / represents a struct field; andStructField.Tag
is a value of type [StructTag
] 6 which describes / represents a tag value.Previously we talked about "convention". This convention means that if you follow it, you may use the
StructTag.Get(key string)
method which parses the value of a tag and returns you the"value"
of thekey
you specify. The convention is implemented / built into thisGet()
method. If you don't follow the convention,Get()
will not be able to parsekey:"value"
pairs and find what you're looking for. That's also not a problem, but then you need to implement your own parsing logic.Also there is
StructTag.Lookup()
(was added in Go 1.7) which is "likeGet()
but distinguishes the tag not containing the given key from the tag associating an empty string with the given key".So let's see a simple example:
Output (try it on the Go Playground):
GopherCon 2015 had a presentation about struct tags called:
The Many Faces of Struct Tags (slide) (and a video)
Here is a list of commonly used tag keys:
json
- used by theencoding/json
package, detailed atjson.Marshal()
xml
- used by theencoding/xml
package, detailed atxml.Marshal()
bson
- used by gobson, detailed atbson.Marshal()
; also by the mongo-go driver, detailed at bson package docprotobuf
- used bygithub.com/golang/protobuf/proto
, detailed in the package docyaml
- used by thegopkg.in/yaml.v2
package, detailed atyaml.Marshal()
db
- used by thegithub.com/jmoiron/sqlx
package; also used bygithub.com/go-gorp/gorp
packageorm
- used by thegithub.com/astaxie/beego/orm
package, detailed at Models – Beego ORMgorm
- used bygorm.io/gorm
, examples can be found in their docsvalid
- used by thegithub.com/asaskevich/govalidator
package, examples can be found in the project pagedatastore
- used byappengine/datastore
(Google App Engine platform, Datastore service), detailed at Propertiesschema
- used bygithub.com/gorilla/schema
to fill astruct
with HTML form values, detailed in the package docasn
- used by theencoding/asn1
package, detailed atasn1.Marshal()
andasn1.Unmarshal()
csv
- used by thegithub.com/gocarina/gocsv
packageenv
- used by thegithub.com/caarlos0/env
package