Hello I am fairly new to visual basic and was wondering if someone could tell me what I'm doing wrong in the ViewData("FirstName") statement??
Public Class HomeController
Inherits System.Web.Mvc.Controller
Private db As cs_dev_ccmetrics_apps = New cs_dev_ccmetrics_apps
Protected Overrides Sub OnActionExecuted(filterContext As ActionExecutedContext)
'APP INFO
'--------------------------
ViewData("Version") = "0.1.7"
ViewData("RevDate") = "08/20/2013"
ViewData("FirstName") =
Select name_first
From users
Where NT_id = System.Environment.UserName
End Sub
I have the model set up like so:
Imports System
Imports System.Collections.Generic
Partial Public Class users
Public Property id As Integer
Public Property domain_id As Byte
Public Property NT_id As String
Public Property emp_id As Integer
Public Property ssn As String
Public Property pwd As String
Public Property admin_role As Byte
Public Property name_last As String
Public Property name_first As String
Public Property last_login As Nullable(Of Date)
Public Property failed_attempts As Byte
Public Property active As Boolean
Public Property dt_updated As Date
End Class
With a dbcontext setup like this:
Imports System
Imports System.Data.Entity
Imports System.Data.Entity.Infrastructure
Partial Public Class cs_dev_ccmetrics_apps
Inherits DbContext
Public Sub New()
MyBase.New("name=cs_dev_ccmetrics_apps")
End Sub
Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)
Throw New UnintentionalCodeFirstException()
End Sub
Public Property app_log() As DbSet(Of app_log)
Public Property ref_AdminRole() As DbSet(Of ref_AdminRole)
Public Property ref_apps() As DbSet(Of ref_apps)
Public Property ref_domains() As DbSet(Of ref_domains)
Public Property user_apps() As DbSet(Of user_apps)
Public Property users() As DbSet(Of users)
End Class
Its been awhile for VB, but I think the syntax should be like the following:
ViewData("FirstName") = db.users.First(function(t) t.NT_id = System.Enviornment.UserName).name_first
Related
I can't get Spring Data Rest with class inheritance working.
I'd like to have a single JSON Endpoint which handles all my concrete classes.
Repo:
public interface AbstractFooRepo extends KeyValueRepository<AbstractFoo, String> {}
Abstract class:
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(value = MyFoo.class, name = "MY_FOO")
})
public abstract class AbstractFoo {
#Id public String id;
public String type;
}
Concrete class:
public class MyFoo extends AbstractFoo { }
Now when calling POST /abstractFoos with {"type":"MY_FOO"}, it tells me: java.lang.IllegalArgumentException: PersistentEntity must not be null!.
This seems to happen, because Spring doesn't know about MyFoo.
Is there some way to tell Spring Data REST about MyFoo without creating a Repository and a REST Endpoint for it?
(I'm using Spring Boot 1.5.1 and Spring Data REST 2.6.0)
EDIT:
Application.java:
#SpringBootApplication
#EnableMapRepositories
public class Application {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
I'm using Spring Boot 1.5.1 and Spring Data Release Ingalls.
KeyValueRepository doesn't work with inheritance. It uses the class name of every saved object to find the corresponding key-value-store. E.g. save(new Foo()) will place the saved object within the Foo collection. And abstractFoosRepo.findAll() will look within the AbstractFoo collection and won't find any Foo object.
Here's the working code using MongoRepository:
Application.java
Default Spring Boot Application Starter.
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
AbstractFoo.java
I've tested include = JsonTypeInfo.As.EXISTING_PROPERTY and include = JsonTypeInfo.As.PROPERTY. Both seem to work fine!
It's even possible to register the Jackson SubTypes with a custom JacksonModule.
IMPORTANT: #RestResource(path="abstractFoos") is highly recommended. Else the _links.self links will point to /foos and /bars instead of /abstractFoos.
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(value = Foo.class, name = "MY_FOO"),
#JsonSubTypes.Type(value = Bar.class, name = "MY_Bar")
})
#Document(collection="foo_collection")
#RestResource(path="abstractFoos")
public abstract class AbstractFoo {
#Id public String id;
public abstract String getType();
}
AbstractFooRepo.java
Nothing special here
public interface AbstractFooRepo extends MongoRepository<AbstractFoo, String> { }
Foo.java & Bar.java
#Persistent
public class Foo extends AbstractFoo {
#Override
public String getType() {
return "MY_FOO";
}
}
#Persistent
public class Bar extends AbstractFoo {
#Override
public String getType() {
return "MY_BAR";
}
}
FooRelProvider.java
Without this part, the output of the objects would be separated in two arrays under _embedded.foos and _embedded.bars.
The supports method ensures that for all classes which extend AbstractFoo, the objects will be placed within _embedded.abstractFoos.
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class FooRelProvider extends EvoInflectorRelProvider {
#Override
public String getCollectionResourceRelFor(final Class<?> type) {
return super.getCollectionResourceRelFor(AbstractFoo.class);
}
#Override
public String getItemResourceRelFor(final Class<?> type) {
return super.getItemResourceRelFor(AbstractFoo.class);
}
#Override
public boolean supports(final Class<?> delimiter) {
return AbstractFoo.class.isAssignableFrom(delimiter);
}
}
EDIT
Added #Persistent to Foo.java and Bar.java. (Adding it to AbstractFoo.java doesn't work). Without this annotation I got NullPointerExceptions when trying to use JSR 303 Validation Annotations within inherited classes.
Example code to reproduce the error:
public class A {
#Id public String id;
#Valid public B b;
// #JsonTypeInfo + #JsonSubTypes
public static abstract class B {
#NotNull public String s;
}
// #Persistent <- Needed!
public static class B1 extends B { }
}
Please see the discussion in this resolved jira task for details of what is currently supported in spring-data-rest regarding JsonTypeInfo. And this jira task on what is still missing.
To summarize - only #JsonTypeInfo with include=JsonTypeInfo.As.EXISTING_PROPERTY is working for serialization and deserialization currently.
Also, you need spring-data-rest 2.5.3 (Hopper SR3) or later to get this limited support.
Please see my sample application - https://github.com/mduesterhoeft/spring-data-rest-entity-inheritance/tree/fixed-hopper-sr3-snapshot
With include=JsonTypeInfo.As.EXISTING_PROPERTY the type information is extracted from a regular property. An example helps getting the point of this way of adding type information:
The abstract class:
#Entity #Inheritance(strategy= SINGLE_TABLE)
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME,
include=JsonTypeInfo.As.EXISTING_PROPERTY,
property="type")
#JsonSubTypes({
#Type(name="DECIMAL", value=DecimalValue.class),
#Type(name="STRING", value=StringValue.class)})
public abstract class Value {
#Id #GeneratedValue(strategy = IDENTITY)
#Getter
private Long id;
public abstract String getType();
}
And the subclass:
#Entity #DiscriminatorValue("D")
#Getter #Setter
public class DecimalValue extends Value {
#Column(name = "DECIMAL_VALUE")
private BigDecimal value;
public String getType() {
return "DECIMAL";
}
}
I have the following MongoDB Repository
public interface TeamRepository extends MongoRepository<Team, TeamId> {
....
}
And the following classes:
public abstract class DbId implements Serializable {
#Id
private final String id;
public DbId(final String id) { this.id = id;}
public String getId() { return id;}
}
public class TeamId extends DbId {
public TeamId(final String id) {
super(id)
}
}
As you can see, I have like a custom id for the repository (I have MongoRepository instead of something like MongoRepository). But, when I am trying to save a Team object, I get an error saying that MongoDB does not know how to generate DBId. Any clue?
MongoDb (or any database) would not know how to generate a string ID without you informing it what the value of the string is.
The default #Id is a string representation of ObjectId, which can be auto-generated by MongoDB. If you are changing the type of string ObjectId to a class, then at least the class needs to define:
** Conversion to string (serialisable), for example:
#Override
public String toString() {
return String.format(
"TeamID[uniqueString=%s]",
myUniqueString);
}
** How to generate the Id.
You can define a method in your TeamRepository i.e. save() to specify how your string can be generated. Alternatively you can check out
https://www.mkyong.com/mongodb/spring-data-mongodb-auto-sequence-id-example/
Where the example specify getNextSequenceId() to generate NumberLong custom id. Hopefully that guides you to your answer.
Is it possible to use Spring's #Value annotation to read and write property values of a custom class type?
For example:
#Component
#PropertySource("classpath:/data.properties")
public class CustomerService {
#Value("${data.isWaiting:#{false}}")
private Boolean isWaiting;
// is this possible for a custom class like Customer???
// Something behind the scenes that converts Custom object to/from property file's string value via an ObjectFactory or something like that?
#Value("${data.customer:#{null}}")
private Customer customer;
...
}
EDITED SOLUTION
Here is how I did it using Spring 4.x APIs...
Created new PropertyEditorSupport class for Customer class:
public class CustomerPropertiesEditor extends PropertyEditorSupport {
// simple mapping class to convert Customer to String and vice-versa.
private CustomerMap map;
#Override
public String getAsText()
{
Customer customer = (Customer) this.getValue();
return map.transform(customer);
}
#Override
public void setAsText(String text) throws IllegalArgumentException
{
Customer customer = map.transform(text);
super.setValue(customer);
}
}
Then in application's ApplicationConfig class:
#Bean
public CustomEditorConfigurer customEditorConfigurer() {
Map<Class<?>, Class<? extends PropertyEditor>> customEditors =
new HashMap<Class<?>, Class<? extends PropertyEditor>>(1);
customEditors.put(Customer.class, CustomerPropertiesEditor.class);
CustomEditorConfigurer configurer = new CustomEditorConfigurer();
configurer.setCustomEditors(customEditors);
return configurer;
}
Cheers,
PM
You have to create a class extending PropertyEditorSupport.
public class CustomerEditor extends PropertyEditorSupport {
#Override
public void setAsText(String text) {
Customer c = new Customer();
// Parse text and set customer fields...
setValue(c);
}
}
It's possible but reading Spring documentation. You could see this example:
Example usage
#Configuration
#PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {
#Autowired
Environment env;
#Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
testBean.setName(env.getProperty("testbean.name"));
return testBean;
}
}
See details here
Spring can read properties and load them directly into a class.
Moreover, you can add #ConfigurationProperties(prefix = "data") on top of the class, instead of wiring each nested property one by one, by making the code cleaner.
Given all that, here is the final example with explanations:
// File: CustomerConfig.java
#Configuration
// Set property source file path (optional)
#PropertySource("classpath:/data.properties")
// Put prefix = "data" here so that Spring read properties under "data.*"
#ConfigurationProperties(prefix = "data")
public class CustomerConfig {
// Note: Property name here is the same as in the file (data.customer)
// Spring will automatically read and put "data.customer.*" properties into this object
private Customer customer;
// Other configs can be added here too... without wiring one-by-one
public setCustomer(Customer customer){
this.customer = customer;
}
public getCustomer(){
return this.customer;
}
}
That's it, now you have "data.customer.*" properties, loaded and accessible via CustomerConfig.getCustomer().
To integrate it into your service (based on your example code):
// File: CustomerService.java
#Component
#PropertySource("classpath:/data.properties")
public class CustomerService {
#Value("${data.isWaiting:#{false}}")
private Boolean isWaiting;
#Autowired // Inject configs, either with #Autowired or using constructor injection
private CustomerConfig customerConfig;
public void myMethod() {
// Now its available for use
System.out.println(customerConfig.getCustomer().toString());
}
}
This way no "magical hack" is required to read configs into a class.
Take a look at the #ConfigurationProperties documentation/examples, and this post for more useful info.
Note: I'd suggest against using PropertyEditorSupport, since
a) it was built for different purpose, may change in future by breaking the code
b) it requires manual "handling" code inside => possible bugs
Instead, use what was built right for that purpose (Spring already has it), in order to both make the code easier to understand, and to gain possible inner improvements/optimizations which might be done in the future (or present).
Further improvements: Your CustomerService seems to be cluttered with configs (#PropertyService) too. I'd suggest reading those properties via another class too (similarly) then wiring that class here, instead of doing all in the CustomerService.
If you want to use it with lists, there is a workaround using array instead.
Define your property as Customer[] instead of List then:
in ApplicationConfig class:
#Bean
public CustomEditorConfigurer customEditorConfigurer() {
Map<Class<?>, Class<? extends PropertyEditor>> customEditors =
new HashMap<Class<?>, Class<? extends PropertyEditor>>(1);
customEditors.put(Customer.class, CustomerPropertiesEditor.class);
customEditors.put(Customer[].class, CustomerPropertiesEditor.class);
CustomEditorConfigurer configurer = new CustomEditorConfigurer();
configurer.setCustomEditors(customEditors);
return configurer;
}
In CustomerEditor:
public class CustomerEditor extends PropertyEditorSupport {
public static final String DEFAULT_SEPARATOR = ",";
#Override
public void setAsText(String text) {
String[] array = StringUtils.delimitedListToStringArray(text, this.separator);
if (this.emptyArrayAsNull && array.length == 0) {
super.setValue((Object) null);
} else {
if (this.trimValues) {
array = StringUtils.trimArrayElements(array);
}
// Convert String[] to Customer[]
super.setValue(...);
}
}
}
If you want to use an existing converter/constructor, you can just call it within your expression.
For example:
#Value("#{T(org.test.CutomerMap).transform('${serialized.customer}')}")
private Customer customer;
Say my command looks like this
public class MyForm {
#Max(99)
private int mode;
private MyObj myObj;
and my MyObj is
public class MyObj {
private String myStr;
private int myInt;
and my controller looks like this
#Controller
public class MyController {
#RequestMapping(value = "/Anything.htm")
public String AnythingMethod(#Valid MyForm myForm, .....
and my JSP looks like this
<form:input path="mode"/>
<form:input path="myObj.myStr"/>
how can I inject validation such as #NotNull #MAx #Min for myStr and myInt? how can I specify their error messages in messages.properties? Please help.
Unsure if the codes posted in your question are complete, you might be missing a few annotations. Also, since you mentioned in your comment that validations on some of the other fields work, I'm going to assume that you have all the dependencies sorted out.
So try this:
In your MyForm class:
public class MyForm {
#Max(99, message="{myform.mode.max}")
private int mode;
#Valid // add #valid annotation
private MyObj myObj;
In your MyObj class:
public class MyObj {
#NotBlank(message="{myobj.mystr.notnull}")
private String myStr;
#Max(/* some value */, message="{myobj.mystr.max}")
#Min(/* some value */, message="{myobj.mystr.min}")
private int myInt;
In your MyController class:
#Controller
public class MyController {
#RequestMapping(value = "/Anything.htm") /* add #ModelAttribute annotation */
public String AnythingMethod(#Valid #ModelAttribute('myForm') MyForm myForm, .....)
As for specifying the error messages in a .properties file, put them all into a ValidationMessages.properties file, and add this file to the root of your classpath. (For e.g., /WEB-INF/classes, resources folder etc.).
Hope this helps.
Can I have a non default multiple argument constructor in toplink. For example
public class Employee {
private String empId;
public Employee(String empId) {
this.empId = empId;
}
}
Yes, however a default constructor must still be available for toplink as well. Toplink uses the default constructor and setters/properties to initialize your object.